From 30bf0f51335e87812ffeb54e9437f0b6a1514d67 Mon Sep 17 00:00:00 2001 From: "Juan J. Martinez" Date: Tue, 6 Sep 2022 07:37:20 +0100 Subject: Updated rasm to 1.7 --- tools/rasm/Makefile | 155 +- tools/rasm/Makefile.orig | 145 + tools/rasm/ReadMe | 19 + tools/rasm/ZX0-main/LICENSE | 29 + tools/rasm/ZX0-main/README.md | 369 + tools/rasm/ZX0-main/src/compress.c | 164 + tools/rasm/ZX0-main/src/memory.c | 75 + tools/rasm/ZX0-main/src/optimize.c | 137 + tools/rasm/ZX0-main/src/zx0.h | 46 + tools/rasm/apultra-master/src/apultra.c | 1035 + tools/rasm/apultra-master/src/expand.c | 396 + tools/rasm/apultra-master/src/expand.h | 71 + tools/rasm/apultra-master/src/format.h | 47 + tools/rasm/apultra-master/src/libapultra.h | 40 + .../apultra-master/src/libdivsufsort/CHANGELOG.md | 21 + .../src/libdivsufsort/CMakeLists.txt | 99 + .../CMakeModules/AppendCompilerFlags.cmake | 38 + .../CMakeModules/CheckFunctionKeywords.cmake | 15 + .../src/libdivsufsort/CMakeModules/CheckLFS.cmake | 109 + .../libdivsufsort/CMakeModules/ProjectCPack.cmake | 38 + .../CMakeModules/cmake_uninstall.cmake.in | 36 + .../rasm/apultra-master/src/libdivsufsort/LICENSE | 21 + .../apultra-master/src/libdivsufsort/README.md | 140 + .../apultra-master/src/libdivsufsort/VERSION.cmake | 23 + .../src/libdivsufsort/examples/CMakeLists.txt | 11 + .../src/libdivsufsort/examples/bwt.c | 220 + .../src/libdivsufsort/examples/mksary.c | 193 + .../src/libdivsufsort/examples/sasearch.c | 165 + .../src/libdivsufsort/examples/suftest.c | 164 + .../src/libdivsufsort/examples/unbwt.c | 207 + .../src/libdivsufsort/include/CMakeLists.txt | 162 + .../src/libdivsufsort/include/config.h.cmake | 81 + .../src/libdivsufsort/include/divsufsort.h | 189 + .../src/libdivsufsort/include/divsufsort.h.cmake | 180 + .../src/libdivsufsort/include/divsufsort_config.h | 9 + .../src/libdivsufsort/include/divsufsort_private.h | 205 + .../src/libdivsufsort/include/lfs.h.cmake | 56 + .../src/libdivsufsort/pkgconfig/CMakeLists.txt | 9 + .../libdivsufsort/pkgconfig/libdivsufsort.pc.cmake | 11 + tools/rasm/apultra-master/src/matchfinder.c | 449 + tools/rasm/apultra-master/src/matchfinder.h | 94 + tools/rasm/apultra-master/src/shrink.c | 1597 ++ tools/rasm/apultra-master/src/shrink.h | 172 + tools/rasm/compil.bat | 28 + tools/rasm/decrunch/aplib_z80_todo.asm | 190 - tools/rasm/decrunch/dzx0_fast.asm | 237 + tools/rasm/decrunch/dzx0_standard.asm | 64 + tools/rasm/decrunch/dzx0_standard_back.asm | 65 + tools/rasm/decrunch/dzx0_turbo_back.asm | 101 + tools/rasm/decrunch/dzx7_turbo.asm | 4 +- tools/rasm/decrunch/exomizer3megachur.asm | 210 - tools/rasm/decrunch/lz48decrunch_v006.asm | 113 - tools/rasm/decrunch/lz48decrunch_v006b.asm | 78 + tools/rasm/decrunch/unaplib.asm | 190 + tools/rasm/decrunch/unaplib_fast.asm | 266 + tools/rasm/decrunch/unlzsa1_fast.asm | 204 + tools/rasm/decrunch/unlzsa2_fast.asm | 189 + tools/rasm/documentation_EN.pdf | Bin 0 -> 278938 bytes tools/rasm/documentation_FR.pdf | Bin 0 -> 292302 bytes tools/rasm/exomizer.h | 1 - tools/rasm/lz4.h | 412 +- tools/rasm/lzsa-master/src/dictionary.c | 101 + tools/rasm/lzsa-master/src/dictionary.h | 64 + tools/rasm/lzsa-master/src/expand_block_v1.c | 224 + tools/rasm/lzsa-master/src/expand_block_v1.h | 49 + tools/rasm/lzsa-master/src/expand_block_v2.c | 253 + tools/rasm/lzsa-master/src/expand_block_v2.h | 49 + tools/rasm/lzsa-master/src/expand_context.c | 76 + tools/rasm/lzsa-master/src/expand_context.h | 61 + tools/rasm/lzsa-master/src/expand_inmem.c | 163 + tools/rasm/lzsa-master/src/expand_inmem.h | 70 + tools/rasm/lzsa-master/src/expand_streaming.c | 236 + tools/rasm/lzsa-master/src/expand_streaming.h | 86 + tools/rasm/lzsa-master/src/format.h | 51 + tools/rasm/lzsa-master/src/frame.c | 189 + tools/rasm/lzsa-master/src/frame.h | 122 + tools/rasm/lzsa-master/src/lib.h | 95 + .../rasm/lzsa-master/src/libdivsufsort/.gitignore | 32 + .../lzsa-master/src/libdivsufsort/CHANGELOG.md | 21 + .../lzsa-master/src/libdivsufsort/CMakeLists.txt | 99 + .../CMakeModules/AppendCompilerFlags.cmake | 38 + .../CMakeModules/CheckFunctionKeywords.cmake | 15 + .../src/libdivsufsort/CMakeModules/CheckLFS.cmake | 109 + .../libdivsufsort/CMakeModules/ProjectCPack.cmake | 38 + .../CMakeModules/cmake_uninstall.cmake.in | 36 + tools/rasm/lzsa-master/src/libdivsufsort/LICENSE | 21 + tools/rasm/lzsa-master/src/libdivsufsort/README.md | 140 + .../lzsa-master/src/libdivsufsort/VERSION.cmake | 23 + .../src/libdivsufsort/examples/CMakeLists.txt | 11 + .../lzsa-master/src/libdivsufsort/examples/bwt.c | 220 + .../src/libdivsufsort/examples/mksary.c | 193 + .../src/libdivsufsort/examples/sasearch.c | 165 + .../src/libdivsufsort/examples/suftest.c | 164 + .../lzsa-master/src/libdivsufsort/examples/unbwt.c | 207 + .../src/libdivsufsort/include/CMakeLists.txt | 162 + .../src/libdivsufsort/include/config.h.cmake | 81 + .../src/libdivsufsort/include/divsufsort.h | 189 + .../src/libdivsufsort/include/divsufsort.h.cmake | 180 + .../src/libdivsufsort/include/divsufsort_config.h | 9 + .../src/libdivsufsort/include/divsufsort_private.h | 205 + .../src/libdivsufsort/include/lfs.h.cmake | 56 + .../src/libdivsufsort/pkgconfig/CMakeLists.txt | 9 + .../libdivsufsort/pkgconfig/libdivsufsort.pc.cmake | 11 + tools/rasm/lzsa-master/src/lzsa.c | 1109 + tools/rasm/lzsa-master/src/matchfinder.c | 361 + tools/rasm/lzsa-master/src/matchfinder.h | 91 + tools/rasm/lzsa-master/src/shrink_block_v1.c | 710 + tools/rasm/lzsa-master/src/shrink_block_v1.h | 53 + tools/rasm/lzsa-master/src/shrink_block_v2.c | 1371 ++ tools/rasm/lzsa-master/src/shrink_block_v2.h | 53 + tools/rasm/lzsa-master/src/shrink_context.c | 254 + tools/rasm/lzsa-master/src/shrink_context.h | 182 + tools/rasm/lzsa-master/src/shrink_inmem.c | 185 + tools/rasm/lzsa-master/src/shrink_inmem.h | 71 + tools/rasm/lzsa-master/src/shrink_streaming.c | 320 + tools/rasm/lzsa-master/src/shrink_streaming.h | 99 + tools/rasm/lzsa-master/src/stream.c | 111 + tools/rasm/lzsa-master/src/stream.h | 103 + tools/rasm/makefile.MacOS | 101 + tools/rasm/minilib.h | 106 +- tools/rasm/msdos.bat | 4 + tools/rasm/rasm.c | 24321 +++++++++++++++++++ tools/rasm/rasm.h | 7 + tools/rasm/rasm_v0120.c | 17472 ------------- tools/rasm/resources/opcodes_first_byte.asm | 542 + tools/rasm/win32.bat | 7 + tools/rasm/zx7.h | 54 +- 127 files changed, 43564 insertions(+), 18240 deletions(-) create mode 100644 tools/rasm/Makefile.orig create mode 100644 tools/rasm/ReadMe create mode 100644 tools/rasm/ZX0-main/LICENSE create mode 100644 tools/rasm/ZX0-main/README.md create mode 100644 tools/rasm/ZX0-main/src/compress.c create mode 100644 tools/rasm/ZX0-main/src/memory.c create mode 100644 tools/rasm/ZX0-main/src/optimize.c create mode 100644 tools/rasm/ZX0-main/src/zx0.h create mode 100644 tools/rasm/apultra-master/src/apultra.c create mode 100644 tools/rasm/apultra-master/src/expand.c create mode 100644 tools/rasm/apultra-master/src/expand.h create mode 100644 tools/rasm/apultra-master/src/format.h create mode 100644 tools/rasm/apultra-master/src/libapultra.h create mode 100644 tools/rasm/apultra-master/src/libdivsufsort/CHANGELOG.md create mode 100644 tools/rasm/apultra-master/src/libdivsufsort/CMakeLists.txt create mode 100644 tools/rasm/apultra-master/src/libdivsufsort/CMakeModules/AppendCompilerFlags.cmake create mode 100644 tools/rasm/apultra-master/src/libdivsufsort/CMakeModules/CheckFunctionKeywords.cmake create mode 100644 tools/rasm/apultra-master/src/libdivsufsort/CMakeModules/CheckLFS.cmake create mode 100644 tools/rasm/apultra-master/src/libdivsufsort/CMakeModules/ProjectCPack.cmake create mode 100644 tools/rasm/apultra-master/src/libdivsufsort/CMakeModules/cmake_uninstall.cmake.in create mode 100644 tools/rasm/apultra-master/src/libdivsufsort/LICENSE create mode 100644 tools/rasm/apultra-master/src/libdivsufsort/README.md create mode 100644 tools/rasm/apultra-master/src/libdivsufsort/VERSION.cmake create mode 100644 tools/rasm/apultra-master/src/libdivsufsort/examples/CMakeLists.txt create mode 100644 tools/rasm/apultra-master/src/libdivsufsort/examples/bwt.c create mode 100644 tools/rasm/apultra-master/src/libdivsufsort/examples/mksary.c create mode 100644 tools/rasm/apultra-master/src/libdivsufsort/examples/sasearch.c create mode 100644 tools/rasm/apultra-master/src/libdivsufsort/examples/suftest.c create mode 100644 tools/rasm/apultra-master/src/libdivsufsort/examples/unbwt.c create mode 100644 tools/rasm/apultra-master/src/libdivsufsort/include/CMakeLists.txt create mode 100644 tools/rasm/apultra-master/src/libdivsufsort/include/config.h.cmake create mode 100644 tools/rasm/apultra-master/src/libdivsufsort/include/divsufsort.h create mode 100644 tools/rasm/apultra-master/src/libdivsufsort/include/divsufsort.h.cmake create mode 100644 tools/rasm/apultra-master/src/libdivsufsort/include/divsufsort_config.h create mode 100644 tools/rasm/apultra-master/src/libdivsufsort/include/divsufsort_private.h create mode 100644 tools/rasm/apultra-master/src/libdivsufsort/include/lfs.h.cmake create mode 100644 tools/rasm/apultra-master/src/libdivsufsort/pkgconfig/CMakeLists.txt create mode 100644 tools/rasm/apultra-master/src/libdivsufsort/pkgconfig/libdivsufsort.pc.cmake create mode 100644 tools/rasm/apultra-master/src/matchfinder.c create mode 100644 tools/rasm/apultra-master/src/matchfinder.h create mode 100644 tools/rasm/apultra-master/src/shrink.c create mode 100644 tools/rasm/apultra-master/src/shrink.h create mode 100644 tools/rasm/compil.bat delete mode 100644 tools/rasm/decrunch/aplib_z80_todo.asm create mode 100644 tools/rasm/decrunch/dzx0_fast.asm create mode 100644 tools/rasm/decrunch/dzx0_standard.asm create mode 100644 tools/rasm/decrunch/dzx0_standard_back.asm create mode 100644 tools/rasm/decrunch/dzx0_turbo_back.asm delete mode 100644 tools/rasm/decrunch/exomizer3megachur.asm delete mode 100644 tools/rasm/decrunch/lz48decrunch_v006.asm create mode 100644 tools/rasm/decrunch/lz48decrunch_v006b.asm create mode 100644 tools/rasm/decrunch/unaplib.asm create mode 100644 tools/rasm/decrunch/unaplib_fast.asm create mode 100644 tools/rasm/decrunch/unlzsa1_fast.asm create mode 100755 tools/rasm/decrunch/unlzsa2_fast.asm create mode 100644 tools/rasm/documentation_EN.pdf create mode 100644 tools/rasm/documentation_FR.pdf create mode 100644 tools/rasm/lzsa-master/src/dictionary.c create mode 100644 tools/rasm/lzsa-master/src/dictionary.h create mode 100644 tools/rasm/lzsa-master/src/expand_block_v1.c create mode 100644 tools/rasm/lzsa-master/src/expand_block_v1.h create mode 100644 tools/rasm/lzsa-master/src/expand_block_v2.c create mode 100644 tools/rasm/lzsa-master/src/expand_block_v2.h create mode 100644 tools/rasm/lzsa-master/src/expand_context.c create mode 100644 tools/rasm/lzsa-master/src/expand_context.h create mode 100644 tools/rasm/lzsa-master/src/expand_inmem.c create mode 100644 tools/rasm/lzsa-master/src/expand_inmem.h create mode 100644 tools/rasm/lzsa-master/src/expand_streaming.c create mode 100644 tools/rasm/lzsa-master/src/expand_streaming.h create mode 100755 tools/rasm/lzsa-master/src/format.h create mode 100644 tools/rasm/lzsa-master/src/frame.c create mode 100644 tools/rasm/lzsa-master/src/frame.h create mode 100755 tools/rasm/lzsa-master/src/lib.h create mode 100644 tools/rasm/lzsa-master/src/libdivsufsort/.gitignore create mode 100644 tools/rasm/lzsa-master/src/libdivsufsort/CHANGELOG.md create mode 100644 tools/rasm/lzsa-master/src/libdivsufsort/CMakeLists.txt create mode 100644 tools/rasm/lzsa-master/src/libdivsufsort/CMakeModules/AppendCompilerFlags.cmake create mode 100644 tools/rasm/lzsa-master/src/libdivsufsort/CMakeModules/CheckFunctionKeywords.cmake create mode 100644 tools/rasm/lzsa-master/src/libdivsufsort/CMakeModules/CheckLFS.cmake create mode 100644 tools/rasm/lzsa-master/src/libdivsufsort/CMakeModules/ProjectCPack.cmake create mode 100644 tools/rasm/lzsa-master/src/libdivsufsort/CMakeModules/cmake_uninstall.cmake.in create mode 100644 tools/rasm/lzsa-master/src/libdivsufsort/LICENSE create mode 100644 tools/rasm/lzsa-master/src/libdivsufsort/README.md create mode 100644 tools/rasm/lzsa-master/src/libdivsufsort/VERSION.cmake create mode 100644 tools/rasm/lzsa-master/src/libdivsufsort/examples/CMakeLists.txt create mode 100644 tools/rasm/lzsa-master/src/libdivsufsort/examples/bwt.c create mode 100644 tools/rasm/lzsa-master/src/libdivsufsort/examples/mksary.c create mode 100644 tools/rasm/lzsa-master/src/libdivsufsort/examples/sasearch.c create mode 100644 tools/rasm/lzsa-master/src/libdivsufsort/examples/suftest.c create mode 100644 tools/rasm/lzsa-master/src/libdivsufsort/examples/unbwt.c create mode 100644 tools/rasm/lzsa-master/src/libdivsufsort/include/CMakeLists.txt create mode 100644 tools/rasm/lzsa-master/src/libdivsufsort/include/config.h.cmake create mode 100755 tools/rasm/lzsa-master/src/libdivsufsort/include/divsufsort.h create mode 100644 tools/rasm/lzsa-master/src/libdivsufsort/include/divsufsort.h.cmake create mode 100644 tools/rasm/lzsa-master/src/libdivsufsort/include/divsufsort_config.h create mode 100644 tools/rasm/lzsa-master/src/libdivsufsort/include/divsufsort_private.h create mode 100644 tools/rasm/lzsa-master/src/libdivsufsort/include/lfs.h.cmake create mode 100644 tools/rasm/lzsa-master/src/libdivsufsort/pkgconfig/CMakeLists.txt create mode 100644 tools/rasm/lzsa-master/src/libdivsufsort/pkgconfig/libdivsufsort.pc.cmake create mode 100755 tools/rasm/lzsa-master/src/lzsa.c create mode 100644 tools/rasm/lzsa-master/src/matchfinder.c create mode 100644 tools/rasm/lzsa-master/src/matchfinder.h create mode 100644 tools/rasm/lzsa-master/src/shrink_block_v1.c create mode 100644 tools/rasm/lzsa-master/src/shrink_block_v1.h create mode 100644 tools/rasm/lzsa-master/src/shrink_block_v2.c create mode 100644 tools/rasm/lzsa-master/src/shrink_block_v2.h create mode 100644 tools/rasm/lzsa-master/src/shrink_context.c create mode 100644 tools/rasm/lzsa-master/src/shrink_context.h create mode 100644 tools/rasm/lzsa-master/src/shrink_inmem.c create mode 100644 tools/rasm/lzsa-master/src/shrink_inmem.h create mode 100644 tools/rasm/lzsa-master/src/shrink_streaming.c create mode 100644 tools/rasm/lzsa-master/src/shrink_streaming.h create mode 100644 tools/rasm/lzsa-master/src/stream.c create mode 100644 tools/rasm/lzsa-master/src/stream.h create mode 100644 tools/rasm/makefile.MacOS create mode 100644 tools/rasm/msdos.bat create mode 100644 tools/rasm/rasm.c delete mode 100644 tools/rasm/rasm_v0120.c create mode 100644 tools/rasm/resources/opcodes_first_byte.asm create mode 100755 tools/rasm/win32.bat (limited to 'tools') diff --git a/tools/rasm/Makefile b/tools/rasm/Makefile index 2fb4627..25d6b31 100644 --- a/tools/rasm/Makefile +++ b/tools/rasm/Makefile @@ -1,21 +1,150 @@ -all: rasm - -CC := gcc -LDFLAGS := -lm -lrt +CC=gcc ifeq ($(OS),Windows_NT) - TARGET := rasm.exe + EXEC=rasm.exe else - TARGET := rasm + EXEC=rasm endif -rasm: rasm_v0120.c - $(CC) $< -s -O2 $(LDFLAGS) -march=native -o $@ - cp $(TARGET) ../../bin - rm -f $(TARGET) +CFLAGS=-lm -lrt -march=native -o $(EXEC) +CFLAGS_OPT = $(CFLAGS) -O2 +CFLAGS_DBG = $(CFLAGS) -g -pthread -DRDD +CFLAGS_3RD = $(CFLAGS) -g -pthread -DNO_3RD_PARTIES -clean: - rm -f $(TARGET) +SRC_APUDIR=./apultra-master/src +SRC_LZSADIR=./lzsa-master/src +SRC_ZX0DIR=./ZX0-main/src + +APU_FLAGS=-c -O3 -fomit-frame-pointer -I$(SRC_LZSADIR)/libdivsufsort/include -I$(SRC_APUDIR) + +APU_OBJ =$(SRC_APUDIR)/expand.o +APU_OBJ+=$(SRC_APUDIR)/matchfinder.o +APU_OBJ+=$(SRC_APUDIR)/shrink.o +APU_OBJ+=$(SRC_APUDIR)/libdivsufsort/lib/divsufsort.o +APU_OBJ+=$(SRC_APUDIR)/libdivsufsort/lib/divsufsort_utils.o +APU_OBJ+=$(SRC_APUDIR)/libdivsufsort/lib/sssort.o +APU_OBJ+=$(SRC_APUDIR)/libdivsufsort/lib/trsort.o + +LZSA_FLAGS=-c -O3 -fomit-frame-pointer -I$(SRC_LZSADIR)/libdivsufsort/include -I$(SRC_LZSADIR) + +LZSA_OBJ =$(SRC_LZSADIR)/dictionary.o +LZSA_OBJ+=$(SRC_LZSADIR)/expand_block_v1.o +LZSA_OBJ+=$(SRC_LZSADIR)/expand_block_v2.o +LZSA_OBJ+=$(SRC_LZSADIR)/expand_context.o +LZSA_OBJ+=$(SRC_LZSADIR)/expand_inmem.o +LZSA_OBJ+=$(SRC_LZSADIR)/frame.o +LZSA_OBJ+=$(SRC_LZSADIR)/matchfinder.o +LZSA_OBJ+=$(SRC_LZSADIR)/shrink_block_v1.o +LZSA_OBJ+=$(SRC_LZSADIR)/shrink_block_v2.o +LZSA_OBJ+=$(SRC_LZSADIR)/shrink_context.o +LZSA_OBJ+=$(SRC_LZSADIR)/shrink_inmem.o +LZSA_OBJ+=$(SRC_LZSADIR)/stream.o + +ZX0_FLAGS=-c -O2 -I$(SRC_ZX0DIR) +ZX0_OBJ =$(SRC_ZX0DIR)/optimize.o +ZX0_OBJ+=$(SRC_ZX0DIR)/compress.o +ZX0_OBJ+=$(SRC_ZX0DIR)/memory.o + +.PHONY: prod third debug clean + +default: prod + cp $(EXEC) ../../bin + rm -f $(EXEC) *.o + +third: + $(CC) rasm.c $(CFLAGS_3RD) + +debug: + $(CC) $(SRC_ZX0DIR)/optimize.c $(ZX0_FLAGS) -o $(SRC_ZX0DIR)/optimize.o + $(CC) $(SRC_ZX0DIR)/compress.c $(ZX0_FLAGS) -o $(SRC_ZX0DIR)/compress.o + $(CC) $(SRC_ZX0DIR)/memory.c $(ZX0_FLAGS) -o $(SRC_ZX0DIR)/memory.o + + $(CC) $(SRC_APUDIR)/expand.c $(APU_FLAGS) -o $(SRC_APUDIR)/expand.o + $(CC) $(SRC_APUDIR)/matchfinder.c $(APU_FLAGS) -o $(SRC_APUDIR)/matchfinder.o + $(CC) $(SRC_APUDIR)/shrink.c $(APU_FLAGS) -o $(SRC_APUDIR)/shrink.o + + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/divsufsort.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/divsufsort.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/divsufsort_utils.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/divsufsort_utils.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/sssort.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/sssort.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/trsort.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/trsort.o -.PHONY: all clean + $(CC) $(SRC_LZSADIR)/matchfinder.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/matchfinder.o + $(CC) $(SRC_LZSADIR)/dictionary.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/dictionary.o + $(CC) $(SRC_LZSADIR)/expand_block_v1.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_block_v1.o + $(CC) $(SRC_LZSADIR)/expand_block_v2.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_block_v2.o + $(CC) $(SRC_LZSADIR)/expand_context.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_context.o + $(CC) $(SRC_LZSADIR)/expand_inmem.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_inmem.o + $(CC) $(SRC_LZSADIR)/frame.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/frame.o + $(CC) $(SRC_LZSADIR)/shrink_block_v1.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_block_v1.o + $(CC) $(SRC_LZSADIR)/shrink_block_v2.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_block_v2.o + $(CC) $(SRC_LZSADIR)/shrink_context.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_context.o + $(CC) $(SRC_LZSADIR)/shrink_inmem.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_inmem.o + $(CC) $(SRC_LZSADIR)/stream.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/stream.o + $(CC) rasm.c $(CFLAGS_DBG) + +prod: + $(CC) $(SRC_ZX0DIR)/optimize.c $(ZX0_FLAGS) -o $(SRC_ZX0DIR)/optimize.o + $(CC) $(SRC_ZX0DIR)/compress.c $(ZX0_FLAGS) -o $(SRC_ZX0DIR)/compress.o + $(CC) $(SRC_ZX0DIR)/memory.c $(ZX0_FLAGS) -o $(SRC_ZX0DIR)/memory.o + + $(CC) $(SRC_APUDIR)/expand.c $(APU_FLAGS) -o $(SRC_APUDIR)/expand.o + $(CC) $(SRC_APUDIR)/matchfinder.c $(APU_FLAGS) -o $(SRC_APUDIR)/matchfinder.o + $(CC) $(SRC_APUDIR)/shrink.c $(APU_FLAGS) -o $(SRC_APUDIR)/shrink.o + + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/divsufsort.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/divsufsort.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/divsufsort_utils.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/divsufsort_utils.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/sssort.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/sssort.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/trsort.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/trsort.o + + $(CC) $(SRC_LZSADIR)/matchfinder.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/matchfinder.o + $(CC) $(SRC_LZSADIR)/dictionary.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/dictionary.o + $(CC) $(SRC_LZSADIR)/expand_block_v1.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_block_v1.o + $(CC) $(SRC_LZSADIR)/expand_block_v2.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_block_v2.o + $(CC) $(SRC_LZSADIR)/expand_context.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_context.o + $(CC) $(SRC_LZSADIR)/expand_inmem.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_inmem.o + $(CC) $(SRC_LZSADIR)/frame.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/frame.o + $(CC) $(SRC_LZSADIR)/shrink_block_v1.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_block_v1.o + $(CC) $(SRC_LZSADIR)/shrink_block_v2.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_block_v2.o + $(CC) $(SRC_LZSADIR)/shrink_context.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_context.o + $(CC) $(SRC_LZSADIR)/shrink_inmem.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_inmem.o + $(CC) $(SRC_LZSADIR)/stream.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/stream.o + + $(CC) rasm.c $(CFLAGS_OPT) $(APU_OBJ) $(LZSA_OBJ) $(ZX0_OBJ) + strip $(EXEC) + +reload: + $(CC) rasm.c $(CFLAGS_OPT) $(APU_OBJ) $(LZSA_OBJ) $(ZX0_OBJ) + strip $(EXEC) + +release: + $(CC) $(SRC_ZX0DIR)/optimize.c $(ZX0_FLAGS) -o $(SRC_ZX0DIR)/optimize.o + $(CC) $(SRC_ZX0DIR)/compress.c $(ZX0_FLAGS) -o $(SRC_ZX0DIR)/compress.o + $(CC) $(SRC_ZX0DIR)/memory.c $(ZX0_FLAGS) -o $(SRC_ZX0DIR)/memory.o + + $(CC) $(SRC_APUDIR)/expand.c $(APU_FLAGS) -o $(SRC_APUDIR)/expand.o + $(CC) $(SRC_APUDIR)/matchfinder.c $(APU_FLAGS) -o $(SRC_APUDIR)/matchfinder.o + $(CC) $(SRC_APUDIR)/shrink.c $(APU_FLAGS) -o $(SRC_APUDIR)/shrink.o + + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/divsufsort.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/divsufsort.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/divsufsort_utils.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/divsufsort_utils.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/sssort.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/sssort.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/trsort.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/trsort.o + + $(CC) $(SRC_LZSADIR)/matchfinder.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/matchfinder.o + $(CC) $(SRC_LZSADIR)/dictionary.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/dictionary.o + $(CC) $(SRC_LZSADIR)/expand_block_v1.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_block_v1.o + $(CC) $(SRC_LZSADIR)/expand_block_v2.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_block_v2.o + $(CC) $(SRC_LZSADIR)/expand_context.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_context.o + $(CC) $(SRC_LZSADIR)/expand_inmem.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_inmem.o + $(CC) $(SRC_LZSADIR)/frame.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/frame.o + $(CC) $(SRC_LZSADIR)/shrink_block_v1.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_block_v1.o + $(CC) $(SRC_LZSADIR)/shrink_block_v2.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_block_v2.o + $(CC) $(SRC_LZSADIR)/shrink_context.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_context.o + $(CC) $(SRC_LZSADIR)/shrink_inmem.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_inmem.o + $(CC) $(SRC_LZSADIR)/stream.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/stream.o + $(CC) rasm.c $(CFLAGS_OPT) $(APU_OBJ) $(LZSA_OBJ) $(ZX0_OBJ) + strip $(EXEC) + +clean: + rm -f *.o $(EXEC) diff --git a/tools/rasm/Makefile.orig b/tools/rasm/Makefile.orig new file mode 100644 index 0000000..ad43112 --- /dev/null +++ b/tools/rasm/Makefile.orig @@ -0,0 +1,145 @@ +CC=cc +EXEC=rasm.exe + +CFLAGS=-lm -lrt -march=native -o $(EXEC) +CFLAGS_OPT = $(CFLAGS) -O2 +CFLAGS_DBG = $(CFLAGS) -g -pthread -DRDD +CFLAGS_3RD = $(CFLAGS) -g -pthread -DNO_3RD_PARTIES + +SRC_APUDIR=./apultra-master/src +SRC_LZSADIR=./lzsa-master/src +SRC_ZX0DIR=./ZX0-main/src + +APU_FLAGS=-c -O3 -fomit-frame-pointer -I$(SRC_LZSADIR)/libdivsufsort/include -I$(SRC_APUDIR) + +APU_OBJ =$(SRC_APUDIR)/expand.o +APU_OBJ+=$(SRC_APUDIR)/matchfinder.o +APU_OBJ+=$(SRC_APUDIR)/shrink.o +APU_OBJ+=$(SRC_APUDIR)/libdivsufsort/lib/divsufsort.o +APU_OBJ+=$(SRC_APUDIR)/libdivsufsort/lib/divsufsort_utils.o +APU_OBJ+=$(SRC_APUDIR)/libdivsufsort/lib/sssort.o +APU_OBJ+=$(SRC_APUDIR)/libdivsufsort/lib/trsort.o + +LZSA_FLAGS=-c -O3 -fomit-frame-pointer -I$(SRC_LZSADIR)/libdivsufsort/include -I$(SRC_LZSADIR) + +LZSA_OBJ =$(SRC_LZSADIR)/dictionary.o +LZSA_OBJ+=$(SRC_LZSADIR)/expand_block_v1.o +LZSA_OBJ+=$(SRC_LZSADIR)/expand_block_v2.o +LZSA_OBJ+=$(SRC_LZSADIR)/expand_context.o +LZSA_OBJ+=$(SRC_LZSADIR)/expand_inmem.o +LZSA_OBJ+=$(SRC_LZSADIR)/frame.o +LZSA_OBJ+=$(SRC_LZSADIR)/matchfinder.o +LZSA_OBJ+=$(SRC_LZSADIR)/shrink_block_v1.o +LZSA_OBJ+=$(SRC_LZSADIR)/shrink_block_v2.o +LZSA_OBJ+=$(SRC_LZSADIR)/shrink_context.o +LZSA_OBJ+=$(SRC_LZSADIR)/shrink_inmem.o +LZSA_OBJ+=$(SRC_LZSADIR)/stream.o + +ZX0_FLAGS=-c -O2 -I$(SRC_ZX0DIR) +ZX0_OBJ =$(SRC_ZX0DIR)/optimize.o +ZX0_OBJ+=$(SRC_ZX0DIR)/compress.o +ZX0_OBJ+=$(SRC_ZX0DIR)/memory.o + +.PHONY: prod third debug clean + +default: prod + +third: + $(CC) rasm.c $(CFLAGS_3RD) + +debug: + $(CC) $(SRC_ZX0DIR)/optimize.c $(ZX0_FLAGS) -o $(SRC_ZX0DIR)/optimize.o + $(CC) $(SRC_ZX0DIR)/compress.c $(ZX0_FLAGS) -o $(SRC_ZX0DIR)/compress.o + $(CC) $(SRC_ZX0DIR)/memory.c $(ZX0_FLAGS) -o $(SRC_ZX0DIR)/memory.o + + $(CC) $(SRC_APUDIR)/expand.c $(APU_FLAGS) -o $(SRC_APUDIR)/expand.o + $(CC) $(SRC_APUDIR)/matchfinder.c $(APU_FLAGS) -o $(SRC_APUDIR)/matchfinder.o + $(CC) $(SRC_APUDIR)/shrink.c $(APU_FLAGS) -o $(SRC_APUDIR)/shrink.o + + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/divsufsort.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/divsufsort.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/divsufsort_utils.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/divsufsort_utils.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/sssort.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/sssort.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/trsort.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/trsort.o + + $(CC) $(SRC_LZSADIR)/matchfinder.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/matchfinder.o + $(CC) $(SRC_LZSADIR)/dictionary.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/dictionary.o + $(CC) $(SRC_LZSADIR)/expand_block_v1.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_block_v1.o + $(CC) $(SRC_LZSADIR)/expand_block_v2.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_block_v2.o + $(CC) $(SRC_LZSADIR)/expand_context.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_context.o + $(CC) $(SRC_LZSADIR)/expand_inmem.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_inmem.o + $(CC) $(SRC_LZSADIR)/frame.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/frame.o + $(CC) $(SRC_LZSADIR)/shrink_block_v1.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_block_v1.o + $(CC) $(SRC_LZSADIR)/shrink_block_v2.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_block_v2.o + $(CC) $(SRC_LZSADIR)/shrink_context.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_context.o + $(CC) $(SRC_LZSADIR)/shrink_inmem.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_inmem.o + $(CC) $(SRC_LZSADIR)/stream.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/stream.o + + $(CC) rasm.c $(CFLAGS_DBG) + +prod: + $(CC) $(SRC_ZX0DIR)/optimize.c $(ZX0_FLAGS) -o $(SRC_ZX0DIR)/optimize.o + $(CC) $(SRC_ZX0DIR)/compress.c $(ZX0_FLAGS) -o $(SRC_ZX0DIR)/compress.o + $(CC) $(SRC_ZX0DIR)/memory.c $(ZX0_FLAGS) -o $(SRC_ZX0DIR)/memory.o + + $(CC) $(SRC_APUDIR)/expand.c $(APU_FLAGS) -o $(SRC_APUDIR)/expand.o + $(CC) $(SRC_APUDIR)/matchfinder.c $(APU_FLAGS) -o $(SRC_APUDIR)/matchfinder.o + $(CC) $(SRC_APUDIR)/shrink.c $(APU_FLAGS) -o $(SRC_APUDIR)/shrink.o + + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/divsufsort.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/divsufsort.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/divsufsort_utils.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/divsufsort_utils.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/sssort.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/sssort.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/trsort.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/trsort.o + + $(CC) $(SRC_LZSADIR)/matchfinder.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/matchfinder.o + $(CC) $(SRC_LZSADIR)/dictionary.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/dictionary.o + $(CC) $(SRC_LZSADIR)/expand_block_v1.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_block_v1.o + $(CC) $(SRC_LZSADIR)/expand_block_v2.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_block_v2.o + $(CC) $(SRC_LZSADIR)/expand_context.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_context.o + $(CC) $(SRC_LZSADIR)/expand_inmem.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_inmem.o + $(CC) $(SRC_LZSADIR)/frame.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/frame.o + $(CC) $(SRC_LZSADIR)/shrink_block_v1.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_block_v1.o + $(CC) $(SRC_LZSADIR)/shrink_block_v2.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_block_v2.o + $(CC) $(SRC_LZSADIR)/shrink_context.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_context.o + $(CC) $(SRC_LZSADIR)/shrink_inmem.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_inmem.o + $(CC) $(SRC_LZSADIR)/stream.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/stream.o + + $(CC) rasm.c $(CFLAGS_OPT) $(APU_OBJ) $(LZSA_OBJ) $(ZX0_OBJ) + strip $(EXEC) + +reload: + $(CC) rasm.c $(CFLAGS_OPT) $(APU_OBJ) $(LZSA_OBJ) $(ZX0_OBJ) + strip $(EXEC) + +release: + $(CC) $(SRC_ZX0DIR)/optimize.c $(ZX0_FLAGS) -o $(SRC_ZX0DIR)/optimize.o + $(CC) $(SRC_ZX0DIR)/compress.c $(ZX0_FLAGS) -o $(SRC_ZX0DIR)/compress.o + $(CC) $(SRC_ZX0DIR)/memory.c $(ZX0_FLAGS) -o $(SRC_ZX0DIR)/memory.o + + $(CC) $(SRC_APUDIR)/expand.c $(APU_FLAGS) -o $(SRC_APUDIR)/expand.o + $(CC) $(SRC_APUDIR)/matchfinder.c $(APU_FLAGS) -o $(SRC_APUDIR)/matchfinder.o + $(CC) $(SRC_APUDIR)/shrink.c $(APU_FLAGS) -o $(SRC_APUDIR)/shrink.o + + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/divsufsort.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/divsufsort.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/divsufsort_utils.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/divsufsort_utils.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/sssort.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/sssort.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/trsort.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/trsort.o + + $(CC) $(SRC_LZSADIR)/matchfinder.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/matchfinder.o + $(CC) $(SRC_LZSADIR)/dictionary.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/dictionary.o + $(CC) $(SRC_LZSADIR)/expand_block_v1.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_block_v1.o + $(CC) $(SRC_LZSADIR)/expand_block_v2.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_block_v2.o + $(CC) $(SRC_LZSADIR)/expand_context.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_context.o + $(CC) $(SRC_LZSADIR)/expand_inmem.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_inmem.o + $(CC) $(SRC_LZSADIR)/frame.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/frame.o + $(CC) $(SRC_LZSADIR)/shrink_block_v1.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_block_v1.o + $(CC) $(SRC_LZSADIR)/shrink_block_v2.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_block_v2.o + $(CC) $(SRC_LZSADIR)/shrink_context.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_context.o + $(CC) $(SRC_LZSADIR)/shrink_inmem.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_inmem.o + $(CC) $(SRC_LZSADIR)/stream.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/stream.o + $(CC) rasm.c $(CFLAGS_OPT) $(APU_OBJ) $(LZSA_OBJ) $(ZX0_OBJ) + strip $(EXEC) + ./upx --brute rasm.exe + +clean: + rm -rf *.o + diff --git a/tools/rasm/ReadMe b/tools/rasm/ReadMe new file mode 100644 index 0000000..7aa21a9 --- /dev/null +++ b/tools/rasm/ReadMe @@ -0,0 +1,19 @@ + +Yes! Another Z80 assembler but this one has... + +- DAMN fast assembling (millions of instructions in a blink of an eye) +- integrated crunched sections (LZ48/LZ49/LZ4/ZX0/ZX7/Exomizer/APlib/LZSA1/LZSA2) + load&crunch on the fly +- CPC cartridge, ZX snapshots, CPC snapshots up to 4M, TAPE output +- save unlimited binaries with or without AMSDOS/HOBETA header +- handle multiple EDSK update or generation simultaneously +- symbols import/export, breakpoint and dependencies export +- ORG checking, unlimited memory workspaces where labels are shared, bank management, structures +- ALL undocumented instructions +- conditionnal macro, unlimited & embeded loops with local labels, switch/case +- floating point engine, mathematical functions, ... +- MAXAM, AS80, UZ80, Pasmo compatibility option +- Amsdos real & Microsoft basic 40bits float support +- English & French documentation + +The project was born a few years ago (2017) because i needed a really fast assembler in order to finish my demo before the deadline of the Alchemy 2017. The project was quite huge with approx 350.000 words to assemble but thanks to rasm, the 512K cartridge compiled in a blink of an eye even on my slow Atom CPU. Now Rasm is the reference for huge projects and ultra-fast assembling. + diff --git a/tools/rasm/ZX0-main/LICENSE b/tools/rasm/ZX0-main/LICENSE new file mode 100644 index 0000000..a0b5162 --- /dev/null +++ b/tools/rasm/ZX0-main/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2021, Einar Saukas +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tools/rasm/ZX0-main/README.md b/tools/rasm/ZX0-main/README.md new file mode 100644 index 0000000..404ac54 --- /dev/null +++ b/tools/rasm/ZX0-main/README.md @@ -0,0 +1,369 @@ +# ZX0 + +**ZX0** is an optimal data compressor for a custom +[LZ77/LZSS](https://en.wikipedia.org/wiki/Lempel%E2%80%93Ziv%E2%80%93Storer%E2%80%93Szymanski) +based compression format, that provides a tradeoff between high compression +ratio, and extremely simple fast decompression. Therefore it's especially +appropriate for low-end platforms, including 8-bit computers like the ZX +Spectrum. + + +## Usage + +To compress a file, use the command-line compressor as follows: + +``` +zx0 Cobra.scr +``` + +This will generate a compressed file called "Cobra.scr.zx0". + +Afterwards you can choose a decompressor routine in assembly Z80, according to +your requirements for speed and size: + +* "Standard" routine: 69 bytes only +* "Turbo" routine: 128 bytes, about 20% faster +* "Mega" routine: 414 bytes, about 25% faster + +Finally compile the chosen decompressor routine and load the compressed file +somewhere in memory. To decompress data, just call the routine specifying the +source address of compressed data in HL and the target address in DE. + +For instance, if you compile the decompressor routine to address 65000, load +"Cobra.scr.zx0" at address 51200, and you want to decompress it directly to the +screen, then execute the following code: + +``` + LD HL, 51200 ; source address (put "Cobra.scr.zx0" there) + LD DE, 16384 ; target address (screen memory in this case) + CALL 65000 ; decompress routine compiled at this address +``` + +It's also possible to decompress data into a memory area that partially overlaps +the compressed data itself (only if you won't need to decompress it again later, +obviously). In this case, the last address of compressed data must be at least +"delta" bytes higher than the last address of decompressed data. The exact value +of "delta" for each case is reported by **ZX0** during compression. See image +below: + +``` + |------------------| compressed data + |---------------------------------| decompressed data + start >> <---> + delta +``` + +For convenience, there's also a command-line decompressor that works as follows: + +``` +dzx0 Cobra.scr.zx0 +``` + + +## Performance + +The **ZX0** optimal compressor algorithm is fairly complex, thus compressing +typical files can take a few seconds. During development, you can speed up this +process simply using **ZX0** in "quick" mode. This will produce a non-optimal +larger compressed file but execute almost instantly: + +``` +zx0 -q Cobra.scr +``` + +This way, you can repeatedly modify your files, then quickly compress and test +them. Later, when you finish changing these files, you can compress them again +without "quick" mode for maximum compression. Notice that using "quick" mode +will only affect the size of the compressed file, not its format. Therefore +all decompressor routines will continue to work exactly the same way. + +Fortunately all complexity lies on the compression process only. The **ZX0** +compression format itself is very simple and efficient, providing a high +compression ratio that can be decompressed quickly and easily. The provided +**ZX0** decompressor routines in assembly Z80 are small and fast, they only use +main registers BC, DE, HL, A and optionally alternate register A' (use the +backwards variant to avoid using A'), consume very little stack space and does +not require additional decompression buffer. + +The provided **ZX0** decompressor in C writes the output file while reading the +compressed file, without keeping it in memory. Therefore it always use the same +amount of memory, regardless of file size. Thus even large compressed files can +be decompressed in very small computers with limited memory, even if it took +considerable time and memory to compress it originally. It means decompressing +within asymptotically optimal space and time O(n) only, using storage space O(n) +for input and output files, and only memory space O(w) for processing. + + +## File Format + +The ZX0 compressed format is very simple. There are only 3 kinds of blocks: + +* Literal (copy next N bytes from compressed file) +``` +0 Elias(length) byte[1] byte[2] ... byte[N] +``` + +* Copy from last offset (repeat N bytes from last offset) +``` +0 Elias(length) +``` + +* Copy from new offset (repeat N bytes from new offset) +``` +1 Elias(MSB(offset)) LSB(offset) Elias(length-1) +``` + +**ZX0** needs only 1 bit to distinguish between these blocks, because literal +blocks cannot be consecutive, and reusing last offset can only happen after a +literal block. The first block is always a literal, so the first bit is omitted. + +The offset MSB and all lengths are stored using interlaced +[Elias Gamma Coding](https://en.wikipedia.org/wiki/Elias_gamma_coding). When +offset MSB equals 256 it means EOF. The offset LSB is stored using 7 bits +instead of 8, because it produces better results in most practical cases. + + +## Advanced Features + +The **ZX0** compressor contains a few extra "hidden" features, that are slightly +harder to use properly, and not supported by the **ZX0** decompressor in C. Please +read carefully these instructions before attempting to use any of them! + + +#### _COMPRESSING BACKWARDS_ + +When using **ZX0** for "in-place" decompression (decompressing data to overlap the +same memory area storing the compressed data), you must always leave a small +margin of "delta" bytes of compressed data at the end. However it won't work to +decompress some large data that will occupy all the upper memory until the last +memory address, since there won't be even a couple bytes left at the end. + +A possible workaround is to compress and decompress data backwards, starting at +the last memory address. Therefore you will only need to leave a small margin of +"delta" bytes of compressed data at the beginning instead. Technically, it will +require that lowest address of compressed data should be at least "delta" bytes +lower than lowest address of decompressed data. See image below: + + compressed data |------------------| + decompressed data |---------------------------------| + <---> << start + delta + +To compress a file backwards, use the command-line compressor as follows: + +``` +zx0 -b Cobra.scr +``` + +To decompress it later, you must call one of the supplied "backwards" variants +of the Assembly decompressor, specifying last source address of compressed data +in HL and last target address in DE. + +For instance, if you compile a "backwards" Assembly decompressor routine to +address 64000, load backwards compressed file "Cobra.scr.zx0" (with size 2202 +bytes) to address 51200, and want to decompress it directly to the ZX Spectrum +screen (with 6912 bytes), then execute the following code: + +``` + LD HL, 51200+2202-1 ; source (last address of "Cobra.scr.zx0") + LD DE, 16384+6912-1 ; target (last address of screen memory) + CALL 64000 ; backwards decompress routine +``` + +Notice that compressing backwards may sometimes produce slightly smaller +compressed files in certain cases, slightly larger compressed files in others. +Overall it shouldn't make much difference either way. + + +#### _COMPRESSING WITH PREFIX_ + +The LZ77/LZSS compression is achieved by "abbreviating repetitions", such that +certain sequences of bytes are replaced with much shorter references to previous +occurrences of these same sequences. For this reason, it's harder to get very +good compression ratio on very short files, or in the initial parts of larger +files, due to lack of choices for previous sequences that could be referenced. + +A possible improvement is to compress data while also taking into account what +else will be already stored in memory during decompression later. Thus the +compressed data may even contain shorter references to repetitions stored in +some previous "prefix" memory area, instead of just repetitions within the +decompressed area itself. + +An input file may contain both some prefix data to be referenced only, and the +actual data to be compressed. An optional parameter can specify how many bytes +must be skipped before compression. See below: + +``` + compressed data + |-------------------| + prefix decompressed data + |--------------|---------------------------------| + start >> + <--------------> <---> + skip delta +``` + +As usual, if you want to decompress data into a memory area that partially +overlaps the compressed data itself, the last address of compressed data must be +at least "delta" bytes higher than the last address of decompressed data. + +For instance, if you want the first 6144 bytes of a certain file to be skipped +(not compressed but possibly referenced), then use the command-line compressor +as follows: + +``` +zx0 +6144 Cobra.cbr +``` + +In practice, suppose an action game uses a few generic sprites that are common +for all levels (such as player graphics), and other sprites are specific for +each level (such as enemies). All generic sprites must stay always accessible at +a certain memory area, but any level specific data can be only decompressed as +needed, to the memory area immediately following it. In this case, the generic +sprites area could be used as prefix when compressing and decompressing each +level, in an attempt to improve compression. For instance, suppose generic +graphics are loaded from file "generic.gfx" to address 56000, occupying 2500 +bytes, and level specific graphics will be decompressed immediately afterwards, +to address 58500. To compress each level using "generic.gfx" as a 2500 bytes +prefix, use the command-line compressor as follows: + +``` +copy /b generic.gfx+level_1.gfx prefixed_level_1.gfx +zx0 +2500 prefixed_level_1.gfx + +copy /b generic.gfx+level_2.gfx prefixed_level_2.gfx +zx0 +2500 prefixed_level_2.gfx + +copy /b generic.gfx+level_3.gfx prefixed_level_3.gfx +zx0 +2500 prefixed_level_3.gfx +``` + +To decompress it later, you simply need to use one of the normal variants of the +Assembly decompressor, as usual. In this case, if you loaded compressed file +"prefixed_level_1.gfx.zx0" to address 48000 for instance, decompressing it will +require the following code: + +``` + LD HL, 48000 ; source address (put "prefixed_level_1.gfx.zx0" there) + LD DE, 58500 ; target address (level specific memory area in this case) + CALL 65000 ; decompress routine compiled at this address +``` + +However decompression will only work properly if exactly the same prefix data is +present in the memory area immediately preceding the decompression address. +Therefore you must be extremely careful to ensure the prefix area does not store +variables, self-modifying code, or anything else that may change prefix content +between compression and decompression. Also don't forget to recompress your +files whenever you modify a prefix! + +In certain cases, compressing with a prefix may considerably help compression. +In others, it may not even make any difference. It mostly depends on how much +similarity exists between data to be compressed and its provided prefix. + + +#### _COMPRESSING BACKWARDS WITH SUFIX_ + +Both features above can be used together. A file can be compressed backwards, +with an optional parameter to specify how many bytes should be skipped (not +compressed but possibly referenced) from the end of the input file instead. See +below: + +``` + compressed data + |-------------------| + decompressed data sufix + |---------------------------------|--------------| + << start + <---> <--------------> + delta skip +``` + +As usual, if you want to decompress data into a memory area that partially +overlaps the compressed data itself, lowest address of compressed data must be +at least "delta" bytes lower than lowest address of decompressed data. + +For instance, if you want to skip the last 768 bytes of a certain input file and +compress everything else (possibly referencing this "sufix" of 768 bytes), then +use the command-line compressor as follows: + +``` +zx0 -b +768 Cobra.cbr +``` + +In previous example, suppose the action game now stores level-specific sprites +in the memory area from address 33000 to 33511 (512 bytes), just before generic +sprites that are stored from address 33512 to 34535 (1024 bytes). In this case, +these generic sprites could be used as sufix when compressing and decompressing +level-specific data as needed, in an attempt to improve compression. To compress +each level using "generic.gfx" as a 1024 bytes sufix, use the command-line +compressor as follows: + +``` +copy /b "level_1.gfx+generic.gfx level_1_sufixed.gfx +zx0 -b +1024 level_1_sufixed.gfx + +copy /b "level_2.gfx+generic.gfx level_2_sufixed.gfx +zx0 -b +1024 level_2_sufixed.gfx + +copy /b "level_3.gfx+generic.gfx level_3_sufixed.gfx +zx0 -b +1024 level_3_sufixed.gfx +``` + +To decompress it later, use the backwards variant of the Assembly decompressor. +In this case, if you compile a "backwards" decompressor routine to address +64000, and load compressed file "level_1_sufixed.gfx.zx0" (with 217 bytes) to +address 39000 for instance, decompressing it will require the following code: + +``` + LD HL, 39000+217-1 ; source (last address of "level_1_sufixed.gfx.zx0") + LD DE, 33000+512-1 ; target (last address of level-specific data) + CALL 64000 ; backwards decompress routine +``` + +Analogously, decompression will only work properly if exactly the same sufix +data is present in the memory area immediately following the decompression area. +Therefore you must be extremely careful to ensure the sufix area does not store +variables, self-modifying code, or anything else that may change sufix content +between compression and decompression. Also don't forget to recompress your +files whenever you modify a sufix! + +Also if you are using "in-place" decompression, you must leave a small margin of +"delta" bytes of compressed data just before the decompression area. + + +## License + +The **ZX0** data compression format and algorithm was designed and implemented +by **Einar Saukas**. Special thanks to **introspec/spke** for several +suggestions and improvements! + +The optimal C compressor is available under the "BSD-3" license. In practice, +this is relevant only if you want to modify its source code and/or incorporate +the compressor within your own products. Otherwise, if you just execute it to +compress files, you can simply ignore these conditions. + +The decompressors can be used freely within your own programs (either for the +ZX Spectrum or any other platform), even for commercial releases. The only +condition is that you must indicate somehow in your documentation that you have +used **ZX0**. + + +## Links + +Projects using **ZX0**: + +* [MSXlib](https://github.com/theNestruo/msx-msxlib) - A set of libraries to +create MSX videogame cartridges, that includes **ZX0** and **ZX7**. + + +Related projects (by the same author): + +* [RCS](https://github.com/einar-saukas/RCS) - Use **ZX0** and **RCS** together +to improve compression of ZX Spectrum screens. + +* [ZX1](https://github.com/einar-saukas/ZX1) - A simpler but faster version +of **ZX0** (**ZX1** sacrifices about 1.5% compression to run about 15% faster). + +* [ZX7](https://spectrumcomputing.co.uk/entry/27996/ZX-Spectrum/ZX7) - A widely +popular predecessor compressor (now superseded by **ZX0**). + diff --git a/tools/rasm/ZX0-main/src/compress.c b/tools/rasm/ZX0-main/src/compress.c new file mode 100644 index 0000000..7feb567 --- /dev/null +++ b/tools/rasm/ZX0-main/src/compress.c @@ -0,0 +1,164 @@ +/* + * (c) Copyright 2021 by Einar Saukas. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The name of its author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "zx0.h" + +unsigned char* output_data; +int output_index; +int input_index; +int bit_index; +int bit_mask; +int diff; +int backtrack; + +void read_bytes(int n, int *delta) { + input_index += n; + diff += n; + if (*delta < diff) + *delta = diff; +} + +void write_byte(int value) { + output_data[output_index++] = value; + diff--; +} + +void write_bit(int value) { + if (backtrack) { + if (value) + output_data[output_index-1] |= 1; + backtrack = FALSE; + } else { + if (!bit_mask) { + bit_mask = 128; + bit_index = output_index; + write_byte(0); + } + if (value) + output_data[bit_index] |= bit_mask; + bit_mask >>= 1; + } +} + +void write_interlaced_elias_gamma(int value, int backwards_mode, int invert_mode) { + int i; + + for (i = 2; i <= value; i <<= 1) + ; + i >>= 1; + while (i >>= 1) { + write_bit(backwards_mode); + write_bit(invert_mode ? !(value & i) : (value & i)); + } + write_bit(!backwards_mode); +} + +unsigned char *zx0_compress(BLOCK *optimal, unsigned char *input_data, int input_size, int skip, int backwards_mode, int invert_mode, int *output_size, int *delta) { + BLOCK *prev; + BLOCK *next; + int last_offset = INITIAL_OFFSET; + int length; + int i; + + /* calculate and allocate output buffer */ + *output_size = (optimal->bits+25)/8; + output_data = (unsigned char *)malloc(*output_size); + if (!output_data) { + fprintf(stderr, "Error: Insufficient memory\n"); + exit(1); + } + + /* un-reverse optimal sequence */ + prev = NULL; + while (optimal) { + next = optimal->chain; + optimal->chain = prev; + prev = optimal; + optimal = next; + } + + /* initialize data */ + diff = *output_size-input_size+skip; + *delta = 0; + input_index = skip; + output_index = 0; + bit_mask = 0; + backtrack = TRUE; + + /* generate output */ + for (optimal = prev->chain; optimal; prev=optimal, optimal = optimal->chain) { + length = optimal->index-prev->index; + + if (!optimal->offset) { + /* copy literals indicator */ + write_bit(0); + + /* copy literals length */ + write_interlaced_elias_gamma(length, backwards_mode, FALSE); + + /* copy literals values */ + for (i = 0; i < length; i++) { + write_byte(input_data[input_index]); + read_bytes(1, delta); + } + } else if (optimal->offset == last_offset) { + /* copy from last offset indicator */ + write_bit(0); + + /* copy from last offset length */ + write_interlaced_elias_gamma(length, backwards_mode, FALSE); + read_bytes(length, delta); + } else { + /* copy from new offset indicator */ + write_bit(1); + + /* copy from new offset MSB */ + write_interlaced_elias_gamma((optimal->offset-1)/128+1, backwards_mode, invert_mode); + + /* copy from new offset LSB */ + if (backwards_mode) + write_byte(((optimal->offset-1)%128)<<1); + else + write_byte((127-(optimal->offset-1)%128)<<1); + + /* copy from new offset length */ + backtrack = TRUE; + write_interlaced_elias_gamma(length-1, backwards_mode, FALSE); + read_bytes(length, delta); + + last_offset = optimal->offset; + } + } + + /* end marker */ + write_bit(1); + write_interlaced_elias_gamma(256, backwards_mode, invert_mode); + + /* done! */ + return output_data; +} diff --git a/tools/rasm/ZX0-main/src/memory.c b/tools/rasm/ZX0-main/src/memory.c new file mode 100644 index 0000000..be52c3a --- /dev/null +++ b/tools/rasm/ZX0-main/src/memory.c @@ -0,0 +1,75 @@ +/* + * (c) Copyright 2021 by Einar Saukas. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The name of its author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "zx0.h" + +#define QTY_BLOCKS 10000 + +BLOCK *ghost_root = NULL; +BLOCK *dead_array = NULL; +int dead_array_size = 0; + +BLOCK *allocate(int bits, int index, int offset, BLOCK *chain) { + BLOCK *ptr; + + if (ghost_root) { + ptr = ghost_root; + ghost_root = ptr->ghost_chain; + if (ptr->chain && !--ptr->chain->references) { + ptr->chain->ghost_chain = ghost_root; + ghost_root = ptr->chain; + } + } else { + if (!dead_array_size) { + dead_array = (BLOCK *)malloc(QTY_BLOCKS*sizeof(BLOCK)); + if (!dead_array) { + fprintf(stderr, "Error: Insufficient memory\n"); + exit(1); + } + dead_array_size = QTY_BLOCKS; + } + ptr = &dead_array[--dead_array_size]; + } + ptr->bits = bits; + ptr->index = index; + ptr->offset = offset; + if (chain) + chain->references++; + ptr->chain = chain; + ptr->references = 0; + return ptr; +} + +void assign(BLOCK **ptr, BLOCK *chain) { + chain->references++; + if (*ptr && !--(*ptr)->references) { + (*ptr)->ghost_chain = ghost_root; + ghost_root = *ptr; + } + *ptr = chain; +} diff --git a/tools/rasm/ZX0-main/src/optimize.c b/tools/rasm/ZX0-main/src/optimize.c new file mode 100644 index 0000000..263837c --- /dev/null +++ b/tools/rasm/ZX0-main/src/optimize.c @@ -0,0 +1,137 @@ +/* + * (c) Copyright 2021 by Einar Saukas. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The name of its author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "zx0.h" + +#define MAX_SCALE 50 + +int offset_ceiling(int index, int offset_limit) { + return index > offset_limit ? offset_limit : index < INITIAL_OFFSET ? INITIAL_OFFSET : index; +} + +int elias_gamma_bits(int value) { + int bits = 1; + while (value >>= 1) + bits += 2; + return bits; +} + +BLOCK* zx0_optimize(unsigned char *input_data, int input_size, int skip, int offset_limit) { + BLOCK **last_literal; + BLOCK **last_match; + BLOCK **optimal; + int* match_length; + int* best_length; + int best_length_size; + int bits; + int index; + int offset; + int length; + int bits2; + int dots = 2; + int max_offset = offset_ceiling(input_size-1, offset_limit); + + /* allocate all main data structures at once */ + last_literal = (BLOCK **)calloc(max_offset+1, sizeof(BLOCK *)); + last_match = (BLOCK **)calloc(max_offset+1, sizeof(BLOCK *)); + optimal = (BLOCK **)calloc(input_size, sizeof(BLOCK *)); + match_length = (int *)calloc(max_offset+1, sizeof(int)); + best_length = (int *)malloc(input_size*sizeof(int)); + if (!last_literal || !last_match || !optimal || !match_length || !best_length) { + fprintf(stderr, "Error: Insufficient memory\n"); + exit(1); + } + best_length[2] = 2; + + /* start with fake block */ + assign(&last_match[INITIAL_OFFSET], allocate(-1, skip-1, INITIAL_OFFSET, NULL)); + + printf("["); + + /* process remaining bytes */ + for (index = skip; index < input_size; index++) { + best_length_size = 2; + max_offset = offset_ceiling(index, offset_limit); + for (offset = 1; offset <= max_offset; offset++) { + if (index != skip && index >= offset && input_data[index] == input_data[index-offset]) { + /* copy from last offset */ + if (last_literal[offset]) { + length = index-last_literal[offset]->index; + bits = last_literal[offset]->bits + 1 + elias_gamma_bits(length); + assign(&last_match[offset], allocate(bits, index, offset, last_literal[offset])); + if (!optimal[index] || optimal[index]->bits > bits) + assign(&optimal[index], last_match[offset]); + } + /* copy from new offset */ + if (++match_length[offset] > 1) { + if (best_length_size < match_length[offset]) { + bits = optimal[index-best_length[best_length_size]]->bits + elias_gamma_bits(best_length[best_length_size]-1); + do { + best_length_size++; + bits2 = optimal[index-best_length_size]->bits + elias_gamma_bits(best_length_size-1); + if (bits2 <= bits) { + best_length[best_length_size] = best_length_size; + bits = bits2; + } else { + best_length[best_length_size] = best_length[best_length_size-1]; + } + } while(best_length_size < match_length[offset]); + } + length = best_length[match_length[offset]]; + bits = optimal[index-length]->bits + 8 + elias_gamma_bits((offset-1)/128+1) + elias_gamma_bits(length-1); + if (!last_match[offset] || last_match[offset]->index != index || last_match[offset]->bits > bits) { + assign(&last_match[offset], allocate(bits, index, offset, optimal[index-length])); + if (!optimal[index] || optimal[index]->bits > bits) + assign(&optimal[index], last_match[offset]); + } + } + } else { + /* copy literals */ + match_length[offset] = 0; + if (last_match[offset]) { + length = index-last_match[offset]->index; + bits = last_match[offset]->bits + 1 + elias_gamma_bits(length) + length*8; + assign(&last_literal[offset], allocate(bits, index, 0, last_match[offset])); + if (!optimal[index] || optimal[index]->bits > bits) + assign(&optimal[index], last_literal[offset]); + } + } + } + + /* indicate progress */ + if (index*MAX_SCALE/input_size > dots) { + printf("."); + fflush(stdout); + dots++; + } + } + + printf("]\n"); + + return optimal[input_size-1]; +} diff --git a/tools/rasm/ZX0-main/src/zx0.h b/tools/rasm/ZX0-main/src/zx0.h new file mode 100644 index 0000000..3b60402 --- /dev/null +++ b/tools/rasm/ZX0-main/src/zx0.h @@ -0,0 +1,46 @@ +/* + * (c) Copyright 2021 by Einar Saukas. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The name of its author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define INITIAL_OFFSET 1 + +#define FALSE 0 +#define TRUE 1 + +typedef struct block_t { + struct block_t *chain; + struct block_t *ghost_chain; + int bits; + int index; + int offset; + int references; +} BLOCK; + +BLOCK *allocate(int bits, int index, int offset, BLOCK *chain); + +void assign(BLOCK **ptr, BLOCK *chain); + +BLOCK *zx0_optimize(unsigned char *input_data, int input_size, int skip, int offset_limit); + +unsigned char *zx0_compress(BLOCK *optimal, unsigned char *input_data, int input_size, int skip, int backwards_mode, int invert_mode, int *output_size, int *delta); diff --git a/tools/rasm/apultra-master/src/apultra.c b/tools/rasm/apultra-master/src/apultra.c new file mode 100644 index 0000000..baababf --- /dev/null +++ b/tools/rasm/apultra-master/src/apultra.c @@ -0,0 +1,1035 @@ +/* + * apultra.c - command line compression utility for the apultra library + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by cap by Sven-Åke Dahl. https://github.com/svendahl/cap + * Also inspired by Charles Bloom's compression blog. http://cbloomrants.blogspot.com/ + * With ideas from LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help and support from spke + * + */ + +#include +#include +#include +#ifdef _WIN32 +#include +#include +#else +#include +#endif +#include "libapultra.h" + +#define OPT_VERBOSE 1 +#define OPT_STATS 2 +#define OPT_BACKWARD 4 + +#define TOOL_VERSION "1.3.6" + +/*---------------------------------------------------------------------------*/ + +#ifdef _WIN32 +LARGE_INTEGER hpc_frequency; +BOOL hpc_available = FALSE; +#endif + +static void do_init_time() { +#ifdef _WIN32 + hpc_frequency.QuadPart = 0; + hpc_available = QueryPerformanceFrequency(&hpc_frequency); +#endif +} + +static long long do_get_time() { + long long nTime; + +#ifdef _WIN32 + if (hpc_available) { + LARGE_INTEGER nCurTime; + + /* Use HPC hardware for best precision */ + QueryPerformanceCounter(&nCurTime); + nTime = (long long)(nCurTime.QuadPart * 1000000LL / hpc_frequency.QuadPart); + } + else { + struct _timeb tb; + _ftime(&tb); + + nTime = ((long long)tb.time * 1000LL + (long long)tb.millitm) * 1000LL; + } +#else + struct timeval tm; + gettimeofday(&tm, NULL); + + nTime = (long long)tm.tv_sec * 1000000LL + (long long)tm.tv_usec; +#endif + return nTime; +} + +static void do_reverse_buffer(unsigned char *pBuffer, size_t nBufferSize) { + size_t nMidPoint = nBufferSize / 2; + size_t i, j; + + for (i = 0, j = nBufferSize - 1; i < nMidPoint; i++, j--) { + unsigned char c = pBuffer[i]; + pBuffer[i] = pBuffer[j]; + pBuffer[j] = c; + } +} + +/*---------------------------------------------------------------------------*/ + +static void compression_progress(long long nOriginalSize, long long nCompressedSize) { + if (nOriginalSize >= 512 * 1024) { + fprintf(stdout, "\r%lld => %lld (%g %%) \b\b\b\b\b", nOriginalSize, nCompressedSize, (double)(nCompressedSize * 100.0 / nOriginalSize)); + fflush(stdout); + } +} + +static int do_compress(const char *pszInFilename, const char *pszOutFilename, const char *pszDictionaryFilename, const unsigned int nOptions, const unsigned int nMaxWindowSize) { + long long nStartTime = 0LL, nEndTime = 0LL; + size_t nOriginalSize = 0L, nCompressedSize = 0L, nMaxCompressedSize; + int nFlags = 0; + apultra_stats stats; + unsigned char *pDecompressedData; + unsigned char *pCompressedData; + + if (nOptions & OPT_VERBOSE) { + nStartTime = do_get_time(); + } + + FILE* f_dict = NULL; + size_t nDictionarySize = 0; + if (pszDictionaryFilename) { + /* Open the dictionary */ + f_dict = fopen(pszDictionaryFilename, "rb"); + if (!f_dict) { + fprintf(stderr, "error opening dictionary '%s' for reading\n", pszDictionaryFilename); + return 100; + } + + /* Get dictionary size */ + fseek(f_dict, 0, SEEK_END); + nDictionarySize = (size_t)ftell(f_dict); + fseek(f_dict, 0, SEEK_SET); + + if (nDictionarySize > BLOCK_SIZE) nDictionarySize = BLOCK_SIZE; + } + + /* Read the whole original file in memory */ + + FILE *f_in = fopen(pszInFilename, "rb"); + if (!f_in) { + if (f_dict) fclose(f_dict); + fprintf(stderr, "error opening '%s' for reading\n", pszInFilename); + return 100; + } + + fseek(f_in, 0, SEEK_END); + nOriginalSize = (size_t)ftell(f_in); + fseek(f_in, 0, SEEK_SET); + + pDecompressedData = (unsigned char*)malloc(nDictionarySize + nOriginalSize); + if (!pDecompressedData) { + fclose(f_in); + if (f_dict) fclose(f_dict); + fprintf(stderr, "out of memory for reading '%s', %zd bytes needed\n", pszInFilename, nOriginalSize); + return 100; + } + + if (f_dict) { + /* Read dictionary data */ + if (fread(pDecompressedData + ((nOptions & OPT_BACKWARD) ? nOriginalSize : 0), 1, nDictionarySize, f_dict) != nDictionarySize) { + free(pDecompressedData); + fclose(f_in); + fclose(f_dict); + fprintf(stderr, "I/O error while reading dictionary '%s'\n", pszDictionaryFilename); + return 100; + } + + fclose(f_dict); + f_dict = NULL; + } + + /* Read input file data */ + if (fread(pDecompressedData + ((nOptions & OPT_BACKWARD) ? 0 : nDictionarySize), 1, nOriginalSize, f_in) != nOriginalSize) { + free(pDecompressedData); + fclose(f_in); + fprintf(stderr, "I/O error while reading '%s'\n", pszInFilename); + return 100; + } + + fclose(f_in); + + if (nOptions & OPT_BACKWARD) + do_reverse_buffer(pDecompressedData, nDictionarySize + nOriginalSize); + + /* Allocate max compressed size */ + + nMaxCompressedSize = apultra_get_max_compressed_size(nDictionarySize + nOriginalSize); + + pCompressedData = (unsigned char*)malloc(nMaxCompressedSize); + if (!pCompressedData) { + free(pDecompressedData); + fprintf(stderr, "out of memory for compressing '%s', %zd bytes needed\n", pszInFilename, nMaxCompressedSize); + return 100; + } + + memset(pCompressedData, 0, nMaxCompressedSize); + + nCompressedSize = apultra_compress(pDecompressedData, pCompressedData, nDictionarySize + nOriginalSize, nMaxCompressedSize, nFlags, nMaxWindowSize, nDictionarySize, compression_progress, &stats); + + if ((nOptions & OPT_VERBOSE)) { + nEndTime = do_get_time(); + } + + if (nCompressedSize == -1) { + free(pCompressedData); + free(pDecompressedData); + fprintf(stderr, "compression error for '%s'\n", pszInFilename); + return 100; + } + + if (nOptions & OPT_BACKWARD) + do_reverse_buffer(pCompressedData, nCompressedSize); + + if (pszOutFilename) { + FILE *f_out; + + /* Write whole compressed file out */ + + f_out = fopen(pszOutFilename, "wb"); + if (f_out) { + fwrite(pCompressedData, 1, nCompressedSize, f_out); + fclose(f_out); + } + } + + free(pCompressedData); + free(pDecompressedData); + + if ((nOptions & OPT_VERBOSE)) { + double fDelta = ((double)(nEndTime - nStartTime)) / 1000000.0; + double fSpeed = ((double)nOriginalSize / 1048576.0) / fDelta; + fprintf(stdout, "\rCompressed '%s' in %g seconds, %.02g Mb/s, %d tokens (%g bytes/token), %d into %d bytes ==> %g %%\n", + pszInFilename, fDelta, fSpeed, stats.commands_divisor, (double)nOriginalSize / (double)stats.commands_divisor, + (int)nOriginalSize, (int)nCompressedSize, (double)(nCompressedSize * 100.0 / nOriginalSize)); + } + + if (nOptions & OPT_STATS) { + fprintf(stdout, "Tokens: literals: %d short matches: %d normal matches: %d large matches: %d rep matches: %d EOD: %d\n", + stats.num_literals, stats.num_4bit_matches, stats.num_7bit_matches, stats.num_variable_matches, stats.num_rep_matches, stats.num_eod); + if (stats.match_divisor > 0) { + fprintf(stdout, "Offsets: min: %d avg: %d max: %d count: %d\n", stats.min_offset, (int)(stats.total_offsets / (long long)stats.match_divisor), stats.max_offset, stats.match_divisor); + fprintf(stdout, "Match lens: min: %d avg: %d max: %d count: %d\n", stats.min_match_len, stats.total_match_lens / stats.match_divisor, stats.max_match_len, stats.match_divisor); + } + else { + fprintf(stdout, "Offsets: none\n"); + fprintf(stdout, "Match lens: none\n"); + } + if (stats.rle1_divisor > 0) { + fprintf(stdout, "RLE1 lens: min: %d avg: %d max: %d count: %d\n", stats.min_rle1_len, stats.total_rle1_lens / stats.rle1_divisor, stats.max_rle1_len, stats.rle1_divisor); + } + else { + fprintf(stdout, "RLE1 lens: none\n"); + } + if (stats.rle2_divisor > 0) { + fprintf(stdout, "RLE2 lens: min: %d avg: %d max: %d count: %d\n", stats.min_rle2_len, stats.total_rle2_lens / stats.rle2_divisor, stats.max_rle2_len, stats.rle2_divisor); + } + else { + fprintf(stdout, "RLE2 lens: none\n"); + } + fprintf(stdout, "Safe distance: %d (0x%X)\n", stats.safe_dist, stats.safe_dist); + } + return 0; +} + +/*---------------------------------------------------------------------------*/ + +static int do_decompress(const char *pszInFilename, const char *pszOutFilename, const char *pszDictionaryFilename, const unsigned int nOptions) { + long long nStartTime = 0LL, nEndTime = 0LL; + size_t nCompressedSize, nMaxDecompressedSize, nOriginalSize; + unsigned char *pCompressedData; + unsigned char *pDecompressedData; + int nFlags = 0; + + /* Read the whole compressed file in memory */ + + FILE *f_in = fopen(pszInFilename, "rb"); + if (!f_in) { + fprintf(stderr, "error opening '%s' for reading\n", pszInFilename); + return 100; + } + + fseek(f_in, 0, SEEK_END); + nCompressedSize = (size_t)ftell(f_in); + fseek(f_in, 0, SEEK_SET); + + pCompressedData = (unsigned char*)malloc(nCompressedSize); + if (!pCompressedData) { + fclose(f_in); + fprintf(stderr, "out of memory for reading '%s', %zd bytes needed\n", pszInFilename, nCompressedSize); + return 100; + } + + if (fread(pCompressedData, 1, nCompressedSize, f_in) != nCompressedSize) { + free(pCompressedData); + fclose(f_in); + fprintf(stderr, "I/O error while reading '%s'\n", pszInFilename); + return 100; + } + + fclose(f_in); + + if (nOptions & OPT_BACKWARD) + do_reverse_buffer(pCompressedData, nCompressedSize); + + /* Get max decompressed size */ + + nMaxDecompressedSize = apultra_get_max_decompressed_size(pCompressedData, nCompressedSize, nFlags); + if (nMaxDecompressedSize == -1) { + free(pCompressedData); + fprintf(stderr, "invalid compressed format for file '%s'\n", pszInFilename); + return 100; + } + + FILE* f_dict = NULL; + size_t nDictionarySize = 0; + if (pszDictionaryFilename) { + /* Open the dictionary */ + f_dict = fopen(pszDictionaryFilename, "rb"); + if (!f_dict) { + fprintf(stderr, "error opening dictionary '%s' for reading\n", pszDictionaryFilename); + return 100; + } + + /* Get dictionary size */ + fseek(f_dict, 0, SEEK_END); + nDictionarySize = (size_t)ftell(f_dict); + fseek(f_dict, 0, SEEK_SET); + + if (nDictionarySize > BLOCK_SIZE) nDictionarySize = BLOCK_SIZE; + } + + /* Allocate max decompressed size */ + + pDecompressedData = (unsigned char*)malloc(nDictionarySize + nMaxDecompressedSize); + if (!pDecompressedData) { + free(pCompressedData); + if (f_dict) fclose(f_dict); + fprintf(stderr, "out of memory for decompressing '%s', %zd bytes needed\n", pszInFilename, nMaxDecompressedSize); + return 100; + } + + memset(pDecompressedData, 0, nDictionarySize + nMaxDecompressedSize); + + if (f_dict) { + /* Read dictionary data */ + if (fread(pDecompressedData, 1, nDictionarySize, f_dict) != nDictionarySize) { + free(pDecompressedData); + fclose(f_in); + fclose(f_dict); + fprintf(stderr, "I/O error while reading dictionary '%s'\n", pszDictionaryFilename); + return 100; + } + + fclose(f_dict); + f_dict = NULL; + + if (nOptions & OPT_BACKWARD) + do_reverse_buffer(pDecompressedData, nDictionarySize); + } + + if (nOptions & OPT_VERBOSE) { + nStartTime = do_get_time(); + } + + nOriginalSize = apultra_decompress(pCompressedData, pDecompressedData, nCompressedSize, nMaxDecompressedSize, nDictionarySize, nFlags); + if (nOriginalSize == -1) { + free(pDecompressedData); + free(pCompressedData); + + fprintf(stderr, "decompression error for '%s'\n", pszInFilename); + return 100; + } + + if (nOptions & OPT_BACKWARD) + do_reverse_buffer(pDecompressedData + nDictionarySize, nOriginalSize); + + if (pszOutFilename) { + FILE *f_out; + + /* Write whole decompressed file out */ + + f_out = fopen(pszOutFilename, "wb"); + if (f_out) { + fwrite(pDecompressedData + nDictionarySize, 1, nOriginalSize, f_out); + fclose(f_out); + } + } + + free(pDecompressedData); + free(pCompressedData); + + if (nOptions & OPT_VERBOSE) { + nEndTime = do_get_time(); + double fDelta = ((double)(nEndTime - nStartTime)) / 1000000.0; + double fSpeed = ((double)nOriginalSize / 1048576.0) / fDelta; + fprintf(stdout, "Decompressed '%s' in %g seconds, %g Mb/s\n", + pszInFilename, fDelta, fSpeed); + } + + return 0; +} + +/*---------------------------------------------------------------------------*/ + +static int do_compare(const char *pszInFilename, const char *pszOutFilename, const char *pszDictionaryFilename, const unsigned int nOptions) { + long long nStartTime = 0LL, nEndTime = 0LL; + size_t nCompressedSize, nMaxDecompressedSize, nOriginalSize, nDecompressedSize; + unsigned char *pCompressedData = NULL; + unsigned char *pOriginalData = NULL; + unsigned char *pDecompressedData = NULL; + int nFlags = 0; + + /* Read the whole compressed file in memory */ + + FILE *f_in = fopen(pszInFilename, "rb"); + if (!f_in) { + fprintf(stderr, "error opening '%s' for reading\n", pszInFilename); + return 100; + } + + fseek(f_in, 0, SEEK_END); + nCompressedSize = (size_t)ftell(f_in); + fseek(f_in, 0, SEEK_SET); + + pCompressedData = (unsigned char*)malloc(nCompressedSize); + if (!pCompressedData) { + fclose(f_in); + fprintf(stderr, "out of memory for reading '%s', %zd bytes needed\n", pszInFilename, nCompressedSize); + return 100; + } + + if (fread(pCompressedData, 1, nCompressedSize, f_in) != nCompressedSize) { + free(pCompressedData); + fclose(f_in); + fprintf(stderr, "I/O error while reading '%s'\n", pszInFilename); + return 100; + } + + fclose(f_in); + + if (nOptions & OPT_BACKWARD) + do_reverse_buffer(pCompressedData, nCompressedSize); + + /* Read the whole original file in memory */ + + f_in = fopen(pszOutFilename, "rb"); + if (!f_in) { + free(pCompressedData); + fprintf(stderr, "error opening '%s' for reading\n", pszInFilename); + return 100; + } + + fseek(f_in, 0, SEEK_END); + nOriginalSize = (size_t)ftell(f_in); + fseek(f_in, 0, SEEK_SET); + + pOriginalData = (unsigned char*)malloc(nOriginalSize); + if (!pOriginalData) { + fclose(f_in); + free(pCompressedData); + fprintf(stderr, "out of memory for reading '%s', %zd bytes needed\n", pszInFilename, nOriginalSize); + return 100; + } + + if (fread(pOriginalData, 1, nOriginalSize, f_in) != nOriginalSize) { + free(pOriginalData); + fclose(f_in); + free(pCompressedData); + fprintf(stderr, "I/O error while reading '%s'\n", pszInFilename); + return 100; + } + + fclose(f_in); + + /* Get max decompressed size */ + + nMaxDecompressedSize = apultra_get_max_decompressed_size(pCompressedData, nCompressedSize, nFlags); + if (nMaxDecompressedSize == -1) { + free(pOriginalData); + free(pCompressedData); + fprintf(stderr, "invalid compressed format for file '%s'\n", pszInFilename); + return 100; + } + + FILE* f_dict = NULL; + size_t nDictionarySize = 0; + if (pszDictionaryFilename) { + /* Open the dictionary */ + f_dict = fopen(pszDictionaryFilename, "rb"); + if (!f_dict) { + fprintf(stderr, "error opening dictionary '%s' for reading\n", pszDictionaryFilename); + return 100; + } + + /* Get dictionary size */ + fseek(f_dict, 0, SEEK_END); + nDictionarySize = (size_t)ftell(f_dict); + fseek(f_dict, 0, SEEK_SET); + + if (nDictionarySize > BLOCK_SIZE) nDictionarySize = BLOCK_SIZE; + } + + /* Allocate max decompressed size */ + + pDecompressedData = (unsigned char*)malloc(nDictionarySize + nMaxDecompressedSize); + if (!pDecompressedData) { + free(pOriginalData); + free(pCompressedData); + if (f_dict) fclose(f_dict); + fprintf(stderr, "out of memory for decompressing '%s', %zd bytes needed\n", pszInFilename, nMaxDecompressedSize); + return 100; + } + + memset(pDecompressedData, 0, nDictionarySize + nMaxDecompressedSize); + + if (f_dict) { + /* Read dictionary data */ + if (fread(pDecompressedData, 1, nDictionarySize, f_dict) != nDictionarySize) { + free(pDecompressedData); + fclose(f_in); + fclose(f_dict); + fprintf(stderr, "I/O error while reading dictionary '%s'\n", pszDictionaryFilename); + return 100; + } + + fclose(f_dict); + f_dict = NULL; + + if (nOptions & OPT_BACKWARD) + do_reverse_buffer(pDecompressedData, nDictionarySize); + } + + if (nOptions & OPT_VERBOSE) { + nStartTime = do_get_time(); + } + + nDecompressedSize = apultra_decompress(pCompressedData, pDecompressedData, nCompressedSize, nMaxDecompressedSize, nDictionarySize, nFlags); + if (nDecompressedSize == -1) { + free(pDecompressedData); + free(pOriginalData); + free(pCompressedData); + + fprintf(stderr, "decompression error for '%s'\n", pszInFilename); + return 100; + } + + if (nOptions & OPT_BACKWARD) + do_reverse_buffer(pDecompressedData + nDictionarySize, nDecompressedSize); + + if (nDecompressedSize != nOriginalSize || memcmp(pDecompressedData + nDictionarySize, pOriginalData, nOriginalSize)) { + fprintf(stderr, "error comparing compressed file '%s' with original '%s'\n", pszInFilename, pszOutFilename); + return 100; + } + + free(pDecompressedData); + free(pOriginalData); + free(pCompressedData); + + if (nOptions & OPT_VERBOSE) { + nEndTime = do_get_time(); + double fDelta = ((double)(nEndTime - nStartTime)) / 1000000.0; + double fSpeed = ((double)nOriginalSize / 1048576.0) / fDelta; + fprintf(stdout, "Compared '%s' in %g seconds, %g Mb/s\n", + pszInFilename, fDelta, fSpeed); + } + + return 0; +} + +/*---------------------------------------------------------------------------*/ + +static void generate_compressible_data(unsigned char *pBuffer, size_t nBufferSize, unsigned int nSeed, int nNumLiteralValues, float fMatchProbability) { + size_t nIndex = 0; + int nMatchProbability = (int)(fMatchProbability * 1023.0f); + + srand(nSeed); + + if (nIndex >= nBufferSize) return; + pBuffer[nIndex++] = rand() % nNumLiteralValues; + + while (nIndex < nBufferSize) { + if ((rand() & 1023) >= nMatchProbability) { + size_t nLiteralCount = rand() & 127; + if (nLiteralCount > (nBufferSize - nIndex)) + nLiteralCount = nBufferSize - nIndex; + + while (nLiteralCount--) + pBuffer[nIndex++] = rand() % nNumLiteralValues; + } + else { + size_t nMatchLength = MIN_MATCH_SIZE + (rand() & 1023); + size_t nMatchOffset; + + if (nMatchLength > (nBufferSize - nIndex)) + nMatchLength = nBufferSize - nIndex; + if (nMatchLength > nIndex) + nMatchLength = nIndex; + + if (nMatchLength < nIndex) + nMatchOffset = rand() % (nIndex - nMatchLength); + else + nMatchOffset = 0; + + while (nMatchLength--) { + pBuffer[nIndex] = pBuffer[nIndex - nMatchOffset]; + nIndex++; + } + } + } +} + +static void xor_data(unsigned char *pBuffer, size_t nBufferSize, unsigned int nSeed, float fXorProbability) { + size_t nIndex = 0; + int nXorProbability = (int)(fXorProbability * 1023.0f); + + srand(nSeed); + + if (nIndex >= nBufferSize) return; + + while (nIndex < nBufferSize) { + if ((rand() & 1023) < nXorProbability) { + pBuffer[nIndex] ^= 0xff; + } + nIndex++; + } +} + +static int do_self_test(const unsigned int nOptions, const unsigned int nMaxWindowSize, const int nIsQuickTest) { + unsigned char *pGeneratedData; + unsigned char *pCompressedData; + unsigned char *pTmpCompressedData; + unsigned char *pTmpDecompressedData; + size_t nGeneratedDataSize; + size_t nMaxCompressedDataSize; + unsigned int nSeed = 123; + int nFlags = 0; + int i; + + pGeneratedData = (unsigned char*)malloc(4 * BLOCK_SIZE); + if (!pGeneratedData) { + fprintf(stderr, "out of memory, %d bytes needed\n", 4 * BLOCK_SIZE); + return 100; + } + + nMaxCompressedDataSize = apultra_get_max_compressed_size(4 * BLOCK_SIZE); + pCompressedData = (unsigned char*)malloc(nMaxCompressedDataSize); + if (!pCompressedData) { + free(pGeneratedData); + pGeneratedData = NULL; + + fprintf(stderr, "out of memory, %zd bytes needed\n", nMaxCompressedDataSize); + return 100; + } + + pTmpCompressedData = (unsigned char*)malloc(nMaxCompressedDataSize); + if (!pTmpCompressedData) { + free(pCompressedData); + pCompressedData = NULL; + free(pGeneratedData); + pGeneratedData = NULL; + + fprintf(stderr, "out of memory, %zd bytes needed\n", nMaxCompressedDataSize); + return 100; + } + + pTmpDecompressedData = (unsigned char*)malloc(4 * BLOCK_SIZE); + if (!pTmpDecompressedData) { + free(pTmpCompressedData); + pTmpCompressedData = NULL; + free(pCompressedData); + pCompressedData = NULL; + free(pGeneratedData); + pGeneratedData = NULL; + + fprintf(stderr, "out of memory, %d bytes needed\n", 4 * BLOCK_SIZE); + return 100; + } + + memset(pGeneratedData, 0, 4 * BLOCK_SIZE); + memset(pCompressedData, 0, nMaxCompressedDataSize); + memset(pTmpCompressedData, 0, nMaxCompressedDataSize); + + /* Test compressing with a too small buffer to do anything, expect to fail cleanly */ + for (i = 0; i < 12; i++) { + generate_compressible_data(pGeneratedData, i, nSeed, 256, 0.5f); + apultra_compress(pGeneratedData, pCompressedData, i, i, nFlags, nMaxWindowSize, 0 /* dictionary size */, NULL, NULL); + } + + size_t nDataSizeStep = 128; + float fProbabilitySizeStep = nIsQuickTest ? 0.005f : 0.0005f; + + for (nGeneratedDataSize = 1024; nGeneratedDataSize <= (nIsQuickTest ? 1024U : (4U * BLOCK_SIZE)); nGeneratedDataSize += nDataSizeStep) { + float fMatchProbability; + + fprintf(stdout, "size %zd", nGeneratedDataSize); + for (fMatchProbability = 0; fMatchProbability <= 0.995f; fMatchProbability += fProbabilitySizeStep) { + int nNumLiteralValues[12] = { 1, 2, 3, 15, 30, 56, 96, 137, 178, 191, 255, 256 }; + float fXorProbability; + + fputc('.', stdout); + fflush(stdout); + + for (i = 0; i < 12; i++) { + /* Generate data to compress */ + generate_compressible_data(pGeneratedData, nGeneratedDataSize, nSeed, nNumLiteralValues[i], fMatchProbability); + + /* Try to compress it, expected to succeed */ + size_t nActualCompressedSize = apultra_compress(pGeneratedData, pCompressedData, nGeneratedDataSize, apultra_get_max_compressed_size(nGeneratedDataSize), + nFlags, nMaxWindowSize, 0 /* dictionary size */, NULL, NULL); + if (nActualCompressedSize == -1 || nActualCompressedSize < (1 + 1 + 1 /* footer */)) { + free(pTmpDecompressedData); + pTmpDecompressedData = NULL; + free(pTmpCompressedData); + pTmpCompressedData = NULL; + free(pCompressedData); + pCompressedData = NULL; + free(pGeneratedData); + pGeneratedData = NULL; + + fprintf(stderr, "\nself-test: error compressing size %zd, seed %d, match probability %f, literals range %d\n", nGeneratedDataSize, nSeed, fMatchProbability, nNumLiteralValues[i]); + return 100; + } + + /* Try to decompress it, expected to succeed */ + size_t nActualDecompressedSize; + nActualDecompressedSize = apultra_decompress(pCompressedData, pTmpDecompressedData, nActualCompressedSize, nGeneratedDataSize, 0 /* dictionary size */, nFlags); + if (nActualDecompressedSize == -1) { + free(pTmpDecompressedData); + pTmpDecompressedData = NULL; + free(pTmpCompressedData); + pTmpCompressedData = NULL; + free(pCompressedData); + pCompressedData = NULL; + free(pGeneratedData); + pGeneratedData = NULL; + + fprintf(stderr, "\nself-test: error decompressing size %zd, seed %d, match probability %f, literals range %d\n", nGeneratedDataSize, nSeed, fMatchProbability, nNumLiteralValues[i]); + return 100; + } + + if (memcmp(pGeneratedData, pTmpDecompressedData, nGeneratedDataSize)) { + free(pTmpDecompressedData); + pTmpDecompressedData = NULL; + free(pTmpCompressedData); + pTmpCompressedData = NULL; + free(pCompressedData); + pCompressedData = NULL; + free(pGeneratedData); + pGeneratedData = NULL; + + fprintf(stderr, "\nself-test: error comparing decompressed and original data, size %zd, seed %d, match probability %f, literals range %d\n", nGeneratedDataSize, nSeed, fMatchProbability, nNumLiteralValues[i]); + return 100; + } + + /* Try to decompress corrupted data, expected to fail cleanly, without crashing or corrupting memory outside the output buffer */ + for (fXorProbability = 0.05f; fXorProbability <= 0.5f; fXorProbability += 0.05f) { + memcpy(pTmpCompressedData, pCompressedData, nActualCompressedSize); + xor_data(pTmpCompressedData, nActualCompressedSize, nSeed, fXorProbability); + apultra_decompress(pTmpCompressedData, pGeneratedData, nActualCompressedSize, nGeneratedDataSize, 0 /* dictionary size */, nFlags); + } + } + + nSeed++; + } + + fputc(10, stdout); + fflush(stdout); + + nDataSizeStep <<= 1; + if (nDataSizeStep > (128 * 4096)) + nDataSizeStep = 128 * 4096; + fProbabilitySizeStep *= 1.25; + if (fProbabilitySizeStep > (0.0005f * 4096)) + fProbabilitySizeStep = 0.0005f * 4096; + } + + free(pTmpDecompressedData); + pTmpDecompressedData = NULL; + + free(pTmpCompressedData); + pTmpCompressedData = NULL; + + free(pCompressedData); + pCompressedData = NULL; + + free(pGeneratedData); + pGeneratedData = NULL; + + fprintf(stdout, "All tests passed.\n"); + return 0; +} + +/*---------------------------------------------------------------------------*/ + +static int do_compr_benchmark(const char *pszInFilename, const char *pszOutFilename, const char *pszDictionaryFilename, const unsigned int nOptions, const unsigned int nMaxWindowSize) { + size_t nFileSize, nMaxCompressedSize; + unsigned char *pFileData; + unsigned char *pCompressedData; + int nFlags = 0; + int i; + + if (pszDictionaryFilename) { + fprintf(stderr, "in-memory benchmarking does not support dictionaries\n"); + return 100; + } + + /* Read the whole original file in memory */ + + FILE *f_in = fopen(pszInFilename, "rb"); + if (!f_in) { + fprintf(stderr, "error opening '%s' for reading\n", pszInFilename); + return 100; + } + + fseek(f_in, 0, SEEK_END); + nFileSize = (size_t)ftell(f_in); + fseek(f_in, 0, SEEK_SET); + + pFileData = (unsigned char*)malloc(nFileSize); + if (!pFileData) { + fclose(f_in); + fprintf(stderr, "out of memory for reading '%s', %zd bytes needed\n", pszInFilename, nFileSize); + return 100; + } + + if (fread(pFileData, 1, nFileSize, f_in) != nFileSize) { + free(pFileData); + fclose(f_in); + fprintf(stderr, "I/O error while reading '%s'\n", pszInFilename); + return 100; + } + + fclose(f_in); + + if (nOptions & OPT_BACKWARD) + do_reverse_buffer(pFileData, nFileSize); + + /* Allocate max compressed size */ + + nMaxCompressedSize = apultra_get_max_compressed_size(nFileSize); + + pCompressedData = (unsigned char*)malloc(nMaxCompressedSize + 2048); + if (!pCompressedData) { + free(pFileData); + fprintf(stderr, "out of memory for compressing '%s', %zd bytes needed\n", pszInFilename, nMaxCompressedSize); + return 100; + } + + memset(pCompressedData + 1024, 0, nMaxCompressedSize); + + long long nBestCompTime = -1; + + size_t nActualCompressedSize = 0; + size_t nRightGuardPos = nMaxCompressedSize; + + for (i = 0; i < 5; i++) { + unsigned char nGuard = 0x33 + i; + int j; + + /* Write guard bytes around the output buffer, to help check for writes outside of it by the compressor */ + memset(pCompressedData, nGuard, 1024); + memset(pCompressedData + 1024 + nRightGuardPos, nGuard, 1024); + + long long t0 = do_get_time(); + nActualCompressedSize = apultra_compress(pFileData, pCompressedData + 1024, nFileSize, nRightGuardPos, nFlags, nMaxWindowSize, 0 /* dictionary size */, NULL, NULL); + long long t1 = do_get_time(); + if (nActualCompressedSize == -1) { + free(pCompressedData); + free(pFileData); + fprintf(stderr, "compression error\n"); + return 100; + } + + long long nCurDecTime = t1 - t0; + if (nBestCompTime == -1 || nBestCompTime > nCurDecTime) + nBestCompTime = nCurDecTime; + + /* Check guard bytes before the output buffer */ + for (j = 0; j < 1024; j++) { + if (pCompressedData[j] != nGuard) { + free(pCompressedData); + free(pFileData); + fprintf(stderr, "error, wrote outside of output buffer at %d!\n", j - 1024); + return 100; + } + } + + /* Check guard bytes after the output buffer */ + for (j = 0; j < 1024; j++) { + if (pCompressedData[1024 + nRightGuardPos + j] != nGuard) { + free(pCompressedData); + free(pFileData); + fprintf(stderr, "error, wrote outside of output buffer at %d!\n", j); + return 100; + } + } + + nRightGuardPos = nActualCompressedSize; + } + + if (nOptions & OPT_BACKWARD) + do_reverse_buffer(pCompressedData + 1024, nActualCompressedSize); + + if (pszOutFilename) { + FILE *f_out; + + /* Write whole compressed file out */ + + f_out = fopen(pszOutFilename, "wb"); + if (f_out) { + fwrite(pCompressedData + 1024, 1, nActualCompressedSize, f_out); + fclose(f_out); + } + } + + free(pCompressedData); + free(pFileData); + + fprintf(stdout, "compressed size: %zd bytes\n", nActualCompressedSize); + fprintf(stdout, "compression time: %lld microseconds (%g Mb/s)\n", nBestCompTime, ((double)nActualCompressedSize / 1024.0) / ((double)nBestCompTime / 1000.0)); + + return 0; +} + +/*---------------------------------------------------------------------------*/ + +static int do_dec_benchmark(const char *pszInFilename, const char *pszOutFilename, const char *pszDictionaryFilename, const unsigned int nOptions) { + size_t nFileSize, nMaxDecompressedSize; + unsigned char *pFileData; + unsigned char *pDecompressedData; + int nFlags = 0; + int i; + + if (pszDictionaryFilename) { + fprintf(stderr, "in-memory benchmarking does not support dictionaries\n"); + return 100; + } + + /* Read the whole compressed file in memory */ + + FILE *f_in = fopen(pszInFilename, "rb"); + if (!f_in) { + fprintf(stderr, "error opening '%s' for reading\n", pszInFilename); + return 100; + } + + fseek(f_in, 0, SEEK_END); + nFileSize = (size_t)ftell(f_in); + fseek(f_in, 0, SEEK_SET); + + pFileData = (unsigned char*)malloc(nFileSize); + if (!pFileData) { + fclose(f_in); + fprintf(stderr, "out of memory for reading '%s', %zd bytes needed\n", pszInFilename, nFileSize); + return 100; + } + + if (fread(pFileData, 1, nFileSize, f_in) != nFileSize) { + free(pFileData); + fclose(f_in); + fprintf(stderr, "I/O error while reading '%s'\n", pszInFilename); + return 100; + } + + fclose(f_in); + + if (nOptions & OPT_BACKWARD) + do_reverse_buffer(pFileData, nFileSize); + + /* Allocate max decompressed size */ + + nMaxDecompressedSize = apultra_get_max_decompressed_size(pFileData, nFileSize, nFlags); + if (nMaxDecompressedSize == -1) { + free(pFileData); + fprintf(stderr, "invalid compressed format for file '%s'\n", pszInFilename); + return 100; + } + + pDecompressedData = (unsigned char*)malloc(nMaxDecompressedSize); + if (!pDecompressedData) { + free(pFileData); + fprintf(stderr, "out of memory for decompressing '%s', %zd bytes needed\n", pszInFilename, nMaxDecompressedSize); + return 100; + } + + memset(pDecompressedData, 0, nMaxDecompressedSize); + + long long nBestDecTime = -1; + + size_t nActualDecompressedSize = 0; + for (i = 0; i < 50; i++) { + long long t0 = do_get_time(); + nActualDecompressedSize = apultra_decompress(pFileData, pDecompressedData, nFileSize, nMaxDecompressedSize, 0 /* dictionary size */, nFlags); + long long t1 = do_get_time(); + if (nActualDecompressedSize == -1) { + free(pDecompressedData); + free(pFileData); + fprintf(stderr, "decompression error\n"); + return 100; + } + + long long nCurDecTime = t1 - t0; + if (nBestDecTime == -1 || nBestDecTime > nCurDecTime) + nBestDecTime = nCurDecTime; + } + + if (nOptions & OPT_BACKWARD) + do_reverse_buffer(pDecompressedData, nActualDecompressedSize); + + if (pszOutFilename) { + FILE *f_out; + + /* Write whole decompressed file out */ + + f_out = fopen(pszOutFilename, "wb"); + if (f_out) { + fwrite(pDecompressedData, 1, nActualDecompressedSize, f_out); + fclose(f_out); + } + } + + free(pDecompressedData); + free(pFileData); + + fprintf(stdout, "decompressed size: %zd bytes\n", nActualDecompressedSize); + fprintf(stdout, "decompression time: %lld microseconds (%g Mb/s)\n", nBestDecTime, ((double)nActualDecompressedSize / 1024.0) / ((double)nBestDecTime / 1000.0)); + + return 0; +} + +/*---------------------------------------------------------------------------*/ + diff --git a/tools/rasm/apultra-master/src/expand.c b/tools/rasm/apultra-master/src/expand.c new file mode 100644 index 0000000..76b3bf1 --- /dev/null +++ b/tools/rasm/apultra-master/src/expand.c @@ -0,0 +1,396 @@ +/* + * expand.c - decompressor implementation + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by cap by Sven-Åke Dahl. https://github.com/svendahl/cap + * Also inspired by Charles Bloom's compression blog. http://cbloomrants.blogspot.com/ + * With ideas from LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help and support from spke + * + */ + +#include +#include +#include "format.h" +#include "expand.h" +#include "libapultra.h" + +#ifdef _MSC_VER +#define FORCE_INLINE __forceinline +#else /* _MSC_VER */ +#define FORCE_INLINE __attribute__((always_inline)) +#endif /* _MSC_VER */ + +static inline FORCE_INLINE int apultra_read_bit(const unsigned char **ppInBlock, const unsigned char *pDataEnd, int *nCurBitMask, unsigned char *bits) { + const unsigned char *pInBlock = *ppInBlock; + int nBit; + + if ((*nCurBitMask) == 0) { + if (pInBlock >= pDataEnd) return -1; + (*bits) = *pInBlock++; + (*nCurBitMask) = 128; + } + + nBit = ((*bits) & 128) ? 1 : 0; + + (*bits) <<= 1; + (*nCurBitMask) >>= 1; + + *ppInBlock = pInBlock; + return nBit; +} + +static inline FORCE_INLINE int apultra_read_gamma2(const unsigned char **ppInBlock, const unsigned char *pDataEnd, int *nCurBitMask, unsigned char *bits) { + int bit; + unsigned int v = 1; + + do { + v = (v << 1) + apultra_read_bit(ppInBlock, pDataEnd, nCurBitMask, bits); + bit = apultra_read_bit(ppInBlock, pDataEnd, nCurBitMask, bits); + if (bit < 0) return bit; + } while (bit); + + return v; +} + +/** + * Get maximum decompressed size of compressed data + * + * @param pInputData compressed data + * @param nInputSize compressed size in bytes + * @param nFlags compression flags (set to 0) + * + * @return maximum decompressed size + */ +size_t apultra_get_max_decompressed_size(const unsigned char *pInputData, size_t nInputSize, const unsigned int nFlags) { + const unsigned char *pInputDataEnd = pInputData + nInputSize; + int nCurBitMask = 0; + unsigned char bits = 0; + int nMatchOffset = -1; + int nFollowsLiteral = 3; + size_t nDecompressedSize = 0; + + if (pInputData >= pInputDataEnd) + return -1; + pInputData++; + nDecompressedSize++; + + while (1) { + unsigned int nResult; + + nResult = apultra_read_bit(&pInputData, pInputDataEnd, &nCurBitMask, &bits); + if (nResult < 0) return -1; + + if (!nResult) { + /* '0': literal */ + if (pInputData < pInputDataEnd) { + pInputData++; + nDecompressedSize++; + nFollowsLiteral = 3; + } + else { + return -1; + } + } + else { + nResult = apultra_read_bit(&pInputData, pInputDataEnd, &nCurBitMask, &bits); + if (nResult < 0) return -1; + + if (nResult == 0) { + unsigned int nMatchLen; + + /* '10': 8+n bits offset */ + int nMatchOffsetHi = apultra_read_gamma2(&pInputData, pInputDataEnd, &nCurBitMask, &bits); + nMatchOffsetHi -= nFollowsLiteral; + if (nMatchOffsetHi >= 0) { + nMatchOffset = ((unsigned int) nMatchOffsetHi) << 8; + nMatchOffset |= (unsigned int)(*pInputData++); + + nMatchLen = apultra_read_gamma2(&pInputData, pInputDataEnd, &nCurBitMask, &bits); + + if (nMatchOffset < 128 || nMatchOffset >= MINMATCH4_OFFSET) + nMatchLen += 2; + else if (nMatchOffset >= MINMATCH3_OFFSET) + nMatchLen++; + } + else { + /* else rep-match */ + nMatchLen = apultra_read_gamma2(&pInputData, pInputDataEnd, &nCurBitMask, &bits); + } + + nFollowsLiteral = 2; + + nDecompressedSize += nMatchLen; + } + else { + nResult = apultra_read_bit(&pInputData, pInputDataEnd, &nCurBitMask, &bits); + if (nResult < 0) return -1; + + if (nResult == 0) { + unsigned int nCommand; + unsigned int nMatchLen; + + /* '110': 7 bits offset + 1 bit length */ + nCommand = (unsigned int)(*pInputData++); + if (nCommand == 0x00) { + /* EOD. No match len follows. */ + break; + } + + /* Bits 7-1: offset; bit 0: length */ + nMatchOffset = (nCommand >> 1); + nMatchLen = (nCommand & 1) + 2; + + nFollowsLiteral = 2; + nDecompressedSize += nMatchLen; + } + else { + unsigned int nShortMatchOffset; + + /* '111': 4 bit offset */ + nResult = apultra_read_bit(&pInputData, pInputDataEnd, &nCurBitMask, &bits); + if (nResult < 0) return -1; + nShortMatchOffset = nResult << 3; + + nResult = apultra_read_bit(&pInputData, pInputDataEnd, &nCurBitMask, &bits); + if (nResult < 0) return -1; + nShortMatchOffset |= nResult << 2; + + nResult = apultra_read_bit(&pInputData, pInputDataEnd, &nCurBitMask, &bits); + if (nResult < 0) return -1; + nShortMatchOffset |= nResult << 1; + + nResult = apultra_read_bit(&pInputData, pInputDataEnd, &nCurBitMask, &bits); + if (nResult < 0) return -1; + nShortMatchOffset |= nResult << 0; + + nFollowsLiteral = 3; + nDecompressedSize++; + } + } + } + } + + return nDecompressedSize; +} + +/** + * Decompress data in memory + * + * @param pInputData compressed data + * @param pOutBuffer buffer for decompressed data + * @param nInputSize compressed size in bytes + * @param nMaxOutBufferSize maximum capacity of decompression buffer + * @param nDictionarySize size of dictionary in front of input data (0 for none) + * @param nFlags compression flags (set to 0) + * + * @return actual decompressed size, or -1 for error + */ +size_t apultra_decompress(const unsigned char *pInputData, unsigned char *pOutData, size_t nInputSize, size_t nMaxOutBufferSize, size_t nDictionarySize, const unsigned int nFlags) { + const unsigned char *pInputDataEnd = pInputData + nInputSize; + unsigned char *pCurOutData = pOutData + nDictionarySize; + const unsigned char *pOutDataEnd = pCurOutData + nMaxOutBufferSize; + const unsigned char *pOutDataFastEnd = pOutDataEnd - 20; + int nCurBitMask = 0; + unsigned char bits = 0; + int nMatchOffset = -1; + int nFollowsLiteral = 3; + + if (pInputData >= pInputDataEnd && pCurOutData < pOutDataEnd) + return -1; + *pCurOutData++ = *pInputData++; + + while (1) { + unsigned int nResult; + + nResult = apultra_read_bit(&pInputData, pInputDataEnd, &nCurBitMask, &bits); + if (nResult < 0) return -1; + + if (!nResult) { + /* '0': literal */ + if (pInputData < pInputDataEnd && pCurOutData < pOutDataEnd) { + *pCurOutData++ = *pInputData++; + nFollowsLiteral = 3; + } + else { + return -1; + } + } + else { + nResult = apultra_read_bit(&pInputData, pInputDataEnd, &nCurBitMask, &bits); + if (nResult < 0) return -1; + + if (nResult == 0) { + unsigned int nMatchLen; + + /* '10': 8+n bits offset */ + int nMatchOffsetHi = apultra_read_gamma2(&pInputData, pInputDataEnd, &nCurBitMask, &bits); + nMatchOffsetHi -= nFollowsLiteral; + if (nMatchOffsetHi >= 0) { + nMatchOffset = ((unsigned int) nMatchOffsetHi) << 8; + nMatchOffset |= (unsigned int)(*pInputData++); + + nMatchLen = apultra_read_gamma2(&pInputData, pInputDataEnd, &nCurBitMask, &bits); + + if (nMatchOffset < 128 || nMatchOffset >= MINMATCH4_OFFSET) + nMatchLen += 2; + else if (nMatchOffset >= MINMATCH3_OFFSET) + nMatchLen++; + } + else { + /* else rep-match */ + nMatchLen = apultra_read_gamma2(&pInputData, pInputDataEnd, &nCurBitMask, &bits); + } + + nFollowsLiteral = 2; + const unsigned char *pSrc = pCurOutData - nMatchOffset; + if (pSrc >= pOutData && (pSrc + nMatchLen) <= pOutDataEnd) { + if (nMatchLen < 11 && nMatchOffset >= 8 && pCurOutData < pOutDataFastEnd) { + memcpy(pCurOutData, pSrc, 8); + memcpy(pCurOutData + 8, pSrc + 8, 2); + pCurOutData += nMatchLen; + } + else { + if ((pCurOutData + nMatchLen) <= pOutDataEnd) { + /* Do a deterministic, left to right byte copy instead of memcpy() so as to handle overlaps */ + + if (nMatchOffset >= 16 && (pCurOutData + nMatchLen) < (pOutDataFastEnd - 15)) { + const unsigned char *pCopySrc = pSrc; + unsigned char *pCopyDst = pCurOutData; + const unsigned char *pCopyEndDst = pCurOutData + nMatchLen; + + do { + memcpy(pCopyDst, pCopySrc, 16); + pCopySrc += 16; + pCopyDst += 16; + } while (pCopyDst < pCopyEndDst); + + pCurOutData += nMatchLen; + } + else { + while (nMatchLen) { + *pCurOutData++ = *pSrc++; + nMatchLen--; + } + } + } + else { + return -1; + } + } + } + else { + return -1; + } + } + else { + nResult = apultra_read_bit(&pInputData, pInputDataEnd, &nCurBitMask, &bits); + if (nResult < 0) return -1; + + if (nResult == 0) { + unsigned int nCommand; + unsigned int nMatchLen; + + /* '110': 7 bits offset + 1 bit length */ + nCommand = (unsigned int)(*pInputData++); + if (nCommand == 0x00) { + /* EOD. No match len follows. */ + break; + } + + /* Bits 7-1: offset; bit 0: length */ + nMatchOffset = (nCommand >> 1); + nMatchLen = (nCommand & 1) + 2; + + nFollowsLiteral = 2; + const unsigned char *pSrc = pCurOutData - nMatchOffset; + if (pSrc >= pOutData && (pSrc + nMatchLen) <= pOutDataEnd) { + if (nMatchOffset >= 8 && pCurOutData < pOutDataFastEnd) { + memcpy(pCurOutData, pSrc, 8); + memcpy(pCurOutData + 8, pSrc + 8, 2); + pCurOutData += nMatchLen; + } + else { + if ((pCurOutData + nMatchLen) <= pOutDataEnd) { + while (nMatchLen) { + *pCurOutData++ = *pSrc++; + nMatchLen--; + } + } + else { + return -1; + } + } + } + else { + return -1; + } + } + else { + unsigned int nShortMatchOffset; + + /* '111': 4 bit offset */ + nResult = apultra_read_bit(&pInputData, pInputDataEnd, &nCurBitMask, &bits); + if (nResult < 0) return -1; + nShortMatchOffset = nResult << 3; + + nResult = apultra_read_bit(&pInputData, pInputDataEnd, &nCurBitMask, &bits); + if (nResult < 0) return -1; + nShortMatchOffset |= nResult << 2; + + nResult = apultra_read_bit(&pInputData, pInputDataEnd, &nCurBitMask, &bits); + if (nResult < 0) return -1; + nShortMatchOffset |= nResult << 1; + + nResult = apultra_read_bit(&pInputData, pInputDataEnd, &nCurBitMask, &bits); + if (nResult < 0) return -1; + nShortMatchOffset |= nResult << 0; + + nFollowsLiteral = 3; + if (nShortMatchOffset) { + /* Short offset, 1-15 */ + const unsigned char *pSrc = pCurOutData - nShortMatchOffset; + if (pSrc >= pOutData && (pCurOutData + 1) <= pOutDataEnd && (pSrc + 1) <= pOutDataEnd) { + *pCurOutData++ = *pSrc++; + } + else { + return -1; + } + } + else { + /* Write zero */ + if ((pCurOutData + 1) <= pOutDataEnd) { + *pCurOutData++ = 0; + } + else { + return -1; + } + } + } + } + } + } + + return (size_t)(pCurOutData - pOutData) - nDictionarySize; +} diff --git a/tools/rasm/apultra-master/src/expand.h b/tools/rasm/apultra-master/src/expand.h new file mode 100644 index 0000000..474660c --- /dev/null +++ b/tools/rasm/apultra-master/src/expand.h @@ -0,0 +1,71 @@ +/* + * expand.h - decompressor definitions + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by cap by Sven-Åke Dahl. https://github.com/svendahl/cap + * Also inspired by Charles Bloom's compression blog. http://cbloomrants.blogspot.com/ + * With ideas from LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help and support from spke + * + */ + +#ifndef _EXPAND_H +#define _EXPAND_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Get maximum decompressed size of compressed data + * + * @param pInputData compressed data + * @param nInputSize compressed size in bytes + * @param nFlags compression flags (set to 0) + * + * @return maximum decompressed size + */ +size_t apultra_get_max_decompressed_size(const unsigned char *pInputData, size_t nInputSize, const unsigned int nFlags); + +/** + * Decompress data in memory + * + * @param pInputData compressed data + * @param pOutBuffer buffer for decompressed data + * @param nInputSize compressed size in bytes + * @param nMaxOutBufferSize maximum capacity of decompression buffer + * @param nDictionarySize size of dictionary in front of input data (0 for none) + * @param nFlags compression flags (set to 0) + * + * @return actual decompressed size, or -1 for error + */ +size_t apultra_decompress(const unsigned char *pInputData, unsigned char *pOutBuffer, size_t nInputSize, size_t nMaxOutBufferSize, size_t nDictionarySize, const unsigned int nFlags); + +#ifdef __cplusplus +} +#endif + +#endif /* _EXPAND_H */ diff --git a/tools/rasm/apultra-master/src/format.h b/tools/rasm/apultra-master/src/format.h new file mode 100644 index 0000000..cf949b5 --- /dev/null +++ b/tools/rasm/apultra-master/src/format.h @@ -0,0 +1,47 @@ +/* + * format.h - byte stream format definitions + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by cap by Sven-Åke Dahl. https://github.com/svendahl/cap + * Also inspired by Charles Bloom's compression blog. http://cbloomrants.blogspot.com/ + * With ideas from LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help and support from spke + * + */ + +#ifndef _FORMAT_H +#define _FORMAT_H + +#define MIN_OFFSET 1 +#define MAX_OFFSET 0x1fffff + +#define MAX_VARLEN 0x1fffff + +#define BLOCK_SIZE 0x100000 + +#define MIN_MATCH_SIZE 1 +#define MINMATCH3_OFFSET 1280 +#define MINMATCH4_OFFSET 32000 + +#endif /* _FORMAT_H */ diff --git a/tools/rasm/apultra-master/src/libapultra.h b/tools/rasm/apultra-master/src/libapultra.h new file mode 100644 index 0000000..f97e336 --- /dev/null +++ b/tools/rasm/apultra-master/src/libapultra.h @@ -0,0 +1,40 @@ +/* + * libapultra.h - library definitions + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by cap by Sven-Åke Dahl. https://github.com/svendahl/cap + * Also inspired by Charles Bloom's compression blog. http://cbloomrants.blogspot.com/ + * With ideas from LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help and support from spke + * + */ + +#ifndef _LIB_APULTRA_H +#define _LIB_APULTRA_H + +#include "format.h" +#include "shrink.h" +#include "expand.h" + +#endif /* _LIB_APULTRA_H */ diff --git a/tools/rasm/apultra-master/src/libdivsufsort/CHANGELOG.md b/tools/rasm/apultra-master/src/libdivsufsort/CHANGELOG.md new file mode 100644 index 0000000..fe9d004 --- /dev/null +++ b/tools/rasm/apultra-master/src/libdivsufsort/CHANGELOG.md @@ -0,0 +1,21 @@ +# libdivsufsort Change Log + +See full changelog at: https://github.com/y-256/libdivsufsort/commits + +## [2.0.1] - 2010-11-11 +### Fixed +* Wrong variable used in `divbwt` function +* Enclose some string variables with double quotation marks in include/CMakeLists.txt +* Fix typo in include/CMakeLists.txt + +## 2.0.0 - 2008-08-23 +### Changed +* Switch the build system to [CMake](http://www.cmake.org/) +* Improve the performance of the suffix-sorting algorithm + +### Added +* OpenMP support +* 64-bit version of divsufsort + +[Unreleased]: https://github.com/y-256/libdivsufsort/compare/2.0.1...HEAD +[2.0.1]: https://github.com/y-256/libdivsufsort/compare/2.0.0...2.0.1 diff --git a/tools/rasm/apultra-master/src/libdivsufsort/CMakeLists.txt b/tools/rasm/apultra-master/src/libdivsufsort/CMakeLists.txt new file mode 100644 index 0000000..7859943 --- /dev/null +++ b/tools/rasm/apultra-master/src/libdivsufsort/CMakeLists.txt @@ -0,0 +1,99 @@ +### cmake file for building libdivsufsort Package ### +cmake_minimum_required(VERSION 2.4.4) +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules") +include(AppendCompilerFlags) + +## Project information ## +project(libdivsufsort C) +set(PROJECT_VENDOR "Yuta Mori") +set(PROJECT_CONTACT "yuta.256@gmail.com") +set(PROJECT_URL "https://github.com/y-256/libdivsufsort") +set(PROJECT_DESCRIPTION "A lightweight suffix sorting library") +include(VERSION.cmake) + +## CPack configuration ## +set(CPACK_GENERATOR "TGZ;TBZ2;ZIP") +set(CPACK_SOURCE_GENERATOR "TGZ;TBZ2;ZIP") +include(ProjectCPack) + +## Project options ## +option(BUILD_SHARED_LIBS "Set to OFF to build static libraries" ON) +option(BUILD_EXAMPLES "Build examples" ON) +option(BUILD_DIVSUFSORT64 "Build libdivsufsort64" OFF) +option(USE_OPENMP "Use OpenMP for parallelization" OFF) +option(WITH_LFS "Enable Large File Support" ON) + +## Installation directories ## +set(LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32 or 64)") + +set(CMAKE_INSTALL_RUNTIMEDIR "" CACHE PATH "Specify the output directory for dll runtimes (default is bin)") +if(NOT CMAKE_INSTALL_RUNTIMEDIR) + set(CMAKE_INSTALL_RUNTIMEDIR "${CMAKE_INSTALL_PREFIX}/bin") +endif(NOT CMAKE_INSTALL_RUNTIMEDIR) + +set(CMAKE_INSTALL_LIBDIR "" CACHE PATH "Specify the output directory for libraries (default is lib)") +if(NOT CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}") +endif(NOT CMAKE_INSTALL_LIBDIR) + +set(CMAKE_INSTALL_INCLUDEDIR "" CACHE PATH "Specify the output directory for header files (default is include)") +if(NOT CMAKE_INSTALL_INCLUDEDIR) + set(CMAKE_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_PREFIX}/include") +endif(NOT CMAKE_INSTALL_INCLUDEDIR) + +set(CMAKE_INSTALL_PKGCONFIGDIR "" CACHE PATH "Specify the output directory for pkgconfig files (default is lib/pkgconfig)") +if(NOT CMAKE_INSTALL_PKGCONFIGDIR) + set(CMAKE_INSTALL_PKGCONFIGDIR "${CMAKE_INSTALL_LIBDIR}/pkgconfig") +endif(NOT CMAKE_INSTALL_PKGCONFIGDIR) + +## Build type ## +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release") +elseif(CMAKE_BUILD_TYPE STREQUAL "Debug") + set(CMAKE_VERBOSE_MAKEFILE ON) +endif(NOT CMAKE_BUILD_TYPE) + +## Compiler options ## +if(MSVC) + append_c_compiler_flags("/W4" "VC" CMAKE_C_FLAGS) + append_c_compiler_flags("/Oi;/Ot;/Ox;/Oy" "VC" CMAKE_C_FLAGS_RELEASE) + if(USE_OPENMP) + append_c_compiler_flags("/openmp" "VC" CMAKE_C_FLAGS) + endif(USE_OPENMP) +elseif(BORLAND) + append_c_compiler_flags("-w" "BCC" CMAKE_C_FLAGS) + append_c_compiler_flags("-Oi;-Og;-Os;-Ov;-Ox" "BCC" CMAKE_C_FLAGS_RELEASE) +else(MSVC) + if(CMAKE_COMPILER_IS_GNUCC) + append_c_compiler_flags("-Wall" "GCC" CMAKE_C_FLAGS) + append_c_compiler_flags("-fomit-frame-pointer" "GCC" CMAKE_C_FLAGS_RELEASE) + if(USE_OPENMP) + append_c_compiler_flags("-fopenmp" "GCC" CMAKE_C_FLAGS) + endif(USE_OPENMP) + else(CMAKE_COMPILER_IS_GNUCC) + append_c_compiler_flags("-Wall" "UNKNOWN" CMAKE_C_FLAGS) + append_c_compiler_flags("-fomit-frame-pointer" "UNKNOWN" CMAKE_C_FLAGS_RELEASE) + if(USE_OPENMP) + append_c_compiler_flags("-fopenmp;-openmp;-omp" "UNKNOWN" CMAKE_C_FLAGS) + endif(USE_OPENMP) + endif(CMAKE_COMPILER_IS_GNUCC) +endif(MSVC) + +## Add definitions ## +add_definitions(-DHAVE_CONFIG_H=1 -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS) + +## Add subdirectories ## +add_subdirectory(pkgconfig) +add_subdirectory(include) +add_subdirectory(lib) +if(BUILD_EXAMPLES) + add_subdirectory(examples) +endif(BUILD_EXAMPLES) + +## Add 'uninstall' target ## +CONFIGURE_FILE( + "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/CMakeModules/cmake_uninstall.cmake" + IMMEDIATE @ONLY) +ADD_CUSTOM_TARGET(uninstall + "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/CMakeModules/cmake_uninstall.cmake") diff --git a/tools/rasm/apultra-master/src/libdivsufsort/CMakeModules/AppendCompilerFlags.cmake b/tools/rasm/apultra-master/src/libdivsufsort/CMakeModules/AppendCompilerFlags.cmake new file mode 100644 index 0000000..58d3f99 --- /dev/null +++ b/tools/rasm/apultra-master/src/libdivsufsort/CMakeModules/AppendCompilerFlags.cmake @@ -0,0 +1,38 @@ +include(CheckCSourceCompiles) +include(CheckCXXSourceCompiles) + +macro(append_c_compiler_flags _flags _name _result) + set(SAFE_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) + string(REGEX REPLACE "[-+/ ]" "_" cname "${_name}") + string(TOUPPER "${cname}" cname) + foreach(flag ${_flags}) + string(REGEX REPLACE "^[-+/ ]+(.*)[-+/ ]*$" "\\1" flagname "${flag}") + string(REGEX REPLACE "[-+/ ]" "_" flagname "${flagname}") + string(TOUPPER "${flagname}" flagname) + set(have_flag "HAVE_${cname}_${flagname}") + set(CMAKE_REQUIRED_FLAGS "${flag}") + check_c_source_compiles("int main() { return 0; }" ${have_flag}) + if(${have_flag}) + set(${_result} "${${_result}} ${flag}") + endif(${have_flag}) + endforeach(flag) + set(CMAKE_REQUIRED_FLAGS ${SAFE_CMAKE_REQUIRED_FLAGS}) +endmacro(append_c_compiler_flags) + +macro(append_cxx_compiler_flags _flags _name _result) + set(SAFE_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) + string(REGEX REPLACE "[-+/ ]" "_" cname "${_name}") + string(TOUPPER "${cname}" cname) + foreach(flag ${_flags}) + string(REGEX REPLACE "^[-+/ ]+(.*)[-+/ ]*$" "\\1" flagname "${flag}") + string(REGEX REPLACE "[-+/ ]" "_" flagname "${flagname}") + string(TOUPPER "${flagname}" flagname) + set(have_flag "HAVE_${cname}_${flagname}") + set(CMAKE_REQUIRED_FLAGS "${flag}") + check_cxx_source_compiles("int main() { return 0; }" ${have_flag}) + if(${have_flag}) + set(${_result} "${${_result}} ${flag}") + endif(${have_flag}) + endforeach(flag) + set(CMAKE_REQUIRED_FLAGS ${SAFE_CMAKE_REQUIRED_FLAGS}) +endmacro(append_cxx_compiler_flags) diff --git a/tools/rasm/apultra-master/src/libdivsufsort/CMakeModules/CheckFunctionKeywords.cmake b/tools/rasm/apultra-master/src/libdivsufsort/CMakeModules/CheckFunctionKeywords.cmake new file mode 100644 index 0000000..44601fd --- /dev/null +++ b/tools/rasm/apultra-master/src/libdivsufsort/CMakeModules/CheckFunctionKeywords.cmake @@ -0,0 +1,15 @@ +include(CheckCSourceCompiles) + +macro(check_function_keywords _wordlist) + set(${_result} "") + foreach(flag ${_wordlist}) + string(REGEX REPLACE "[-+/ ()]" "_" flagname "${flag}") + string(TOUPPER "${flagname}" flagname) + set(have_flag "HAVE_${flagname}") + check_c_source_compiles("${flag} void func(); void func() { } int main() { func(); return 0; }" ${have_flag}) + if(${have_flag} AND NOT ${_result}) + set(${_result} "${flag}") +# break() + endif(${have_flag} AND NOT ${_result}) + endforeach(flag) +endmacro(check_function_keywords) diff --git a/tools/rasm/apultra-master/src/libdivsufsort/CMakeModules/CheckLFS.cmake b/tools/rasm/apultra-master/src/libdivsufsort/CMakeModules/CheckLFS.cmake new file mode 100644 index 0000000..e2b0099 --- /dev/null +++ b/tools/rasm/apultra-master/src/libdivsufsort/CMakeModules/CheckLFS.cmake @@ -0,0 +1,109 @@ +## Checks for large file support ## +include(CheckIncludeFile) +include(CheckSymbolExists) +include(CheckTypeSize) + +macro(check_lfs _isenable) + set(LFS_OFF_T "") + set(LFS_FOPEN "") + set(LFS_FSEEK "") + set(LFS_FTELL "") + set(LFS_PRID "") + + if(${_isenable}) + set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}") + set(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} + -D_LARGEFILE_SOURCE -D_LARGE_FILES -D_FILE_OFFSET_BITS=64 + -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS) + + check_include_file("sys/types.h" HAVE_SYS_TYPES_H) + check_include_file("inttypes.h" HAVE_INTTYPES_H) + check_include_file("stddef.h" HAVE_STDDEF_H) + check_include_file("stdint.h" HAVE_STDINT_H) + + # LFS type1: 8 <= sizeof(off_t), fseeko, ftello + check_type_size("off_t" SIZEOF_OFF_T) + if(SIZEOF_OFF_T GREATER 7) + check_symbol_exists("fseeko" "stdio.h" HAVE_FSEEKO) + check_symbol_exists("ftello" "stdio.h" HAVE_FTELLO) + if(HAVE_FSEEKO AND HAVE_FTELLO) + set(LFS_OFF_T "off_t") + set(LFS_FOPEN "fopen") + set(LFS_FSEEK "fseeko") + set(LFS_FTELL "ftello") + check_symbol_exists("PRIdMAX" "inttypes.h" HAVE_PRIDMAX) + if(HAVE_PRIDMAX) + set(LFS_PRID "PRIdMAX") + else(HAVE_PRIDMAX) + check_type_size("long" SIZEOF_LONG) + check_type_size("int" SIZEOF_INT) + if(SIZEOF_OFF_T GREATER SIZEOF_LONG) + set(LFS_PRID "\"lld\"") + elseif(SIZEOF_LONG GREATER SIZEOF_INT) + set(LFS_PRID "\"ld\"") + else(SIZEOF_OFF_T GREATER SIZEOF_LONG) + set(LFS_PRID "\"d\"") + endif(SIZEOF_OFF_T GREATER SIZEOF_LONG) + endif(HAVE_PRIDMAX) + endif(HAVE_FSEEKO AND HAVE_FTELLO) + endif(SIZEOF_OFF_T GREATER 7) + + # LFS type2: 8 <= sizeof(off64_t), fopen64, fseeko64, ftello64 + if(NOT LFS_OFF_T) + check_type_size("off64_t" SIZEOF_OFF64_T) + if(SIZEOF_OFF64_T GREATER 7) + check_symbol_exists("fopen64" "stdio.h" HAVE_FOPEN64) + check_symbol_exists("fseeko64" "stdio.h" HAVE_FSEEKO64) + check_symbol_exists("ftello64" "stdio.h" HAVE_FTELLO64) + if(HAVE_FOPEN64 AND HAVE_FSEEKO64 AND HAVE_FTELLO64) + set(LFS_OFF_T "off64_t") + set(LFS_FOPEN "fopen64") + set(LFS_FSEEK "fseeko64") + set(LFS_FTELL "ftello64") + check_symbol_exists("PRIdMAX" "inttypes.h" HAVE_PRIDMAX) + if(HAVE_PRIDMAX) + set(LFS_PRID "PRIdMAX") + else(HAVE_PRIDMAX) + check_type_size("long" SIZEOF_LONG) + check_type_size("int" SIZEOF_INT) + if(SIZEOF_OFF64_T GREATER SIZEOF_LONG) + set(LFS_PRID "\"lld\"") + elseif(SIZEOF_LONG GREATER SIZEOF_INT) + set(LFS_PRID "\"ld\"") + else(SIZEOF_OFF64_T GREATER SIZEOF_LONG) + set(LFS_PRID "\"d\"") + endif(SIZEOF_OFF64_T GREATER SIZEOF_LONG) + endif(HAVE_PRIDMAX) + endif(HAVE_FOPEN64 AND HAVE_FSEEKO64 AND HAVE_FTELLO64) + endif(SIZEOF_OFF64_T GREATER 7) + endif(NOT LFS_OFF_T) + + # LFS type3: 8 <= sizeof(__int64), _fseeki64, _ftelli64 + if(NOT LFS_OFF_T) + check_type_size("__int64" SIZEOF___INT64) + if(SIZEOF___INT64 GREATER 7) + check_symbol_exists("_fseeki64" "stdio.h" HAVE__FSEEKI64) + check_symbol_exists("_ftelli64" "stdio.h" HAVE__FTELLI64) + if(HAVE__FSEEKI64 AND HAVE__FTELLI64) + set(LFS_OFF_T "__int64") + set(LFS_FOPEN "fopen") + set(LFS_FSEEK "_fseeki64") + set(LFS_FTELL "_ftelli64") + set(LFS_PRID "\"I64d\"") + endif(HAVE__FSEEKI64 AND HAVE__FTELLI64) + endif(SIZEOF___INT64 GREATER 7) + endif(NOT LFS_OFF_T) + + set(CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}") + endif(${_isenable}) + + if(NOT LFS_OFF_T) + ## not found + set(LFS_OFF_T "long") + set(LFS_FOPEN "fopen") + set(LFS_FSEEK "fseek") + set(LFS_FTELL "ftell") + set(LFS_PRID "\"ld\"") + endif(NOT LFS_OFF_T) + +endmacro(check_lfs) diff --git a/tools/rasm/apultra-master/src/libdivsufsort/CMakeModules/ProjectCPack.cmake b/tools/rasm/apultra-master/src/libdivsufsort/CMakeModules/ProjectCPack.cmake new file mode 100644 index 0000000..7c105f9 --- /dev/null +++ b/tools/rasm/apultra-master/src/libdivsufsort/CMakeModules/ProjectCPack.cmake @@ -0,0 +1,38 @@ +# If the cmake version includes cpack, use it +IF(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") + SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PROJECT_DESCRIPTION}") + SET(CPACK_PACKAGE_VENDOR "${PROJECT_VENDOR}") + SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md") + SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") + SET(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}") + SET(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}") + SET(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}") +# SET(CPACK_PACKAGE_INSTALL_DIRECTORY "${PROJECT_NAME} ${PROJECT_VERSION}") + SET(CPACK_SOURCE_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION_FULL}") + + IF(NOT DEFINED CPACK_SYSTEM_NAME) + SET(CPACK_SYSTEM_NAME "${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}") + ENDIF(NOT DEFINED CPACK_SYSTEM_NAME) + + IF(${CPACK_SYSTEM_NAME} MATCHES Windows) + IF(CMAKE_CL_64) + SET(CPACK_SYSTEM_NAME win64-${CMAKE_SYSTEM_PROCESSOR}) + ELSE(CMAKE_CL_64) + SET(CPACK_SYSTEM_NAME win32-${CMAKE_SYSTEM_PROCESSOR}) + ENDIF(CMAKE_CL_64) + ENDIF(${CPACK_SYSTEM_NAME} MATCHES Windows) + + IF(NOT DEFINED CPACK_PACKAGE_FILE_NAME) + SET(CPACK_PACKAGE_FILE_NAME "${CPACK_SOURCE_PACKAGE_FILE_NAME}-${CPACK_SYSTEM_NAME}") + ENDIF(NOT DEFINED CPACK_PACKAGE_FILE_NAME) + + SET(CPACK_PACKAGE_CONTACT "${PROJECT_CONTACT}") + IF(UNIX) + SET(CPACK_STRIP_FILES "") + SET(CPACK_SOURCE_STRIP_FILES "") +# SET(CPACK_PACKAGE_EXECUTABLES "ccmake" "CMake") + ENDIF(UNIX) + SET(CPACK_SOURCE_IGNORE_FILES "/CVS/" "/build/" "/\\\\.build/" "/\\\\.svn/" "~$") + # include CPack model once all variables are set + INCLUDE(CPack) +ENDIF(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") diff --git a/tools/rasm/apultra-master/src/libdivsufsort/CMakeModules/cmake_uninstall.cmake.in b/tools/rasm/apultra-master/src/libdivsufsort/CMakeModules/cmake_uninstall.cmake.in new file mode 100644 index 0000000..8366a83 --- /dev/null +++ b/tools/rasm/apultra-master/src/libdivsufsort/CMakeModules/cmake_uninstall.cmake.in @@ -0,0 +1,36 @@ +IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") +ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + +FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +STRING(REGEX REPLACE "\n" ";" files "${files}") + +SET(NUM 0) +FOREACH(file ${files}) + IF(EXISTS "$ENV{DESTDIR}${file}") + MESSAGE(STATUS "Looking for \"$ENV{DESTDIR}${file}\" - found") + SET(UNINSTALL_CHECK_${NUM} 1) + ELSE(EXISTS "$ENV{DESTDIR}${file}") + MESSAGE(STATUS "Looking for \"$ENV{DESTDIR}${file}\" - not found") + SET(UNINSTALL_CHECK_${NUM} 0) + ENDIF(EXISTS "$ENV{DESTDIR}${file}") + MATH(EXPR NUM "1 + ${NUM}") +ENDFOREACH(file) + +SET(NUM 0) +FOREACH(file ${files}) + IF(${UNINSTALL_CHECK_${NUM}}) + MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") + EXEC_PROGRAM( + "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + IF(NOT "${rm_retval}" STREQUAL 0) + MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") + ENDIF(NOT "${rm_retval}" STREQUAL 0) + ENDIF(${UNINSTALL_CHECK_${NUM}}) + MATH(EXPR NUM "1 + ${NUM}") +ENDFOREACH(file) + +FILE(REMOVE "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") diff --git a/tools/rasm/apultra-master/src/libdivsufsort/LICENSE b/tools/rasm/apultra-master/src/libdivsufsort/LICENSE new file mode 100644 index 0000000..249efa4 --- /dev/null +++ b/tools/rasm/apultra-master/src/libdivsufsort/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2003 Yuta Mori 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. diff --git a/tools/rasm/apultra-master/src/libdivsufsort/README.md b/tools/rasm/apultra-master/src/libdivsufsort/README.md new file mode 100644 index 0000000..381a188 --- /dev/null +++ b/tools/rasm/apultra-master/src/libdivsufsort/README.md @@ -0,0 +1,140 @@ +# libdivsufsort + +libdivsufsort is a software library that implements a lightweight suffix array construction algorithm. + +## News +* 2015-03-21: The project has moved from [Google Code](http://code.google.com/p/libdivsufsort/) to [GitHub](https://github.com/y-256/libdivsufsort) + +## Introduction +This library provides a simple and an efficient C API to construct a suffix array and a Burrows-Wheeler transformed string from a given string over a constant-size alphabet. +The algorithm runs in O(n log n) worst-case time using only 5n+O(1) bytes of memory space, where n is the length of +the string. + +## Build requirements +* An ANSI C Compiler (e.g. GNU GCC) +* [CMake](http://www.cmake.org/ "CMake") version 2.4.2 or newer +* CMake-supported build tool + +## Building on GNU/Linux +1. Get the source code from GitHub. You can either + * use git to clone the repository + ``` + git clone https://github.com/y-256/libdivsufsort.git + ``` + * or download a [zip file](../../archive/master.zip) directly +2. Create a `build` directory in the package source directory. +```shell +$ cd libdivsufsort +$ mkdir build +$ cd build +``` +3. Configure the package for your system. +If you want to install to a different location, change the -DCMAKE_INSTALL_PREFIX option. +```shell +$ cmake -DCMAKE_BUILD_TYPE="Release" \ +-DCMAKE_INSTALL_PREFIX="/usr/local" .. +``` +4. Compile the package. +```shell +$ make +``` +5. (Optional) Install the library and header files. +```shell +$ sudo make install +``` + +## API +```c +/* Data types */ +typedef int32_t saint_t; +typedef int32_t saidx_t; +typedef uint8_t sauchar_t; + +/* + * Constructs the suffix array of a given string. + * @param T[0..n-1] The input string. + * @param SA[0..n-1] The output array or suffixes. + * @param n The length of the given string. + * @return 0 if no error occurred, -1 or -2 otherwise. + */ +saint_t +divsufsort(const sauchar_t *T, saidx_t *SA, saidx_t n); + +/* + * Constructs the burrows-wheeler transformed string of a given string. + * @param T[0..n-1] The input string. + * @param U[0..n-1] The output string. (can be T) + * @param A[0..n-1] The temporary array. (can be NULL) + * @param n The length of the given string. + * @return The primary index if no error occurred, -1 or -2 otherwise. + */ +saidx_t +divbwt(const sauchar_t *T, sauchar_t *U, saidx_t *A, saidx_t n); +``` + +## Example Usage +```c +#include +#include +#include + +#include + +int main() { + // intput data + char *Text = "abracadabra"; + int n = strlen(Text); + int i, j; + + // allocate + int *SA = (int *)malloc(n * sizeof(int)); + + // sort + divsufsort((unsigned char *)Text, SA, n); + + // output + for(i = 0; i < n; ++i) { + printf("SA[%2d] = %2d: ", i, SA[i]); + for(j = SA[i]; j < n; ++j) { + printf("%c", Text[j]); + } + printf("$\n"); + } + + // deallocate + free(SA); + + return 0; +} +``` +See the [examples](examples) directory for a few other examples. + +## Benchmarks +See [Benchmarks](https://github.com/y-256/libdivsufsort/blob/wiki/SACA_Benchmarks.md) page for details. + +## License +libdivsufsort is released under the [MIT license](LICENSE "MIT license"). +> The MIT License (MIT) +> +> Copyright (c) 2003 Yuta Mori 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. + +## Author +* Yuta Mori diff --git a/tools/rasm/apultra-master/src/libdivsufsort/VERSION.cmake b/tools/rasm/apultra-master/src/libdivsufsort/VERSION.cmake new file mode 100644 index 0000000..3f11ac1 --- /dev/null +++ b/tools/rasm/apultra-master/src/libdivsufsort/VERSION.cmake @@ -0,0 +1,23 @@ +set(PROJECT_VERSION_MAJOR "2") +set(PROJECT_VERSION_MINOR "0") +set(PROJECT_VERSION_PATCH "2") +set(PROJECT_VERSION_EXTRA "-1") +set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}") +set(PROJECT_VERSION_FULL "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${PROJECT_VERSION_EXTRA}") + +set(LIBRARY_VERSION "3.0.1") +set(LIBRARY_SOVERSION "3") + +## Git revision number ## +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git") + execute_process(COMMAND git describe --tags HEAD + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + OUTPUT_VARIABLE GIT_DESCRIBE_TAGS ERROR_QUIET) + if(GIT_DESCRIBE_TAGS) + string(REGEX REPLACE "^v(.*)" "\\1" GIT_REVISION "${GIT_DESCRIBE_TAGS}") + string(STRIP "${GIT_REVISION}" GIT_REVISION) + if(GIT_REVISION) + set(PROJECT_VERSION_FULL "${GIT_REVISION}") + endif(GIT_REVISION) + endif(GIT_DESCRIBE_TAGS) +endif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git") diff --git a/tools/rasm/apultra-master/src/libdivsufsort/examples/CMakeLists.txt b/tools/rasm/apultra-master/src/libdivsufsort/examples/CMakeLists.txt new file mode 100644 index 0000000..e801c81 --- /dev/null +++ b/tools/rasm/apultra-master/src/libdivsufsort/examples/CMakeLists.txt @@ -0,0 +1,11 @@ +## Add definitions ## +add_definitions(-D_LARGEFILE_SOURCE -D_LARGE_FILES -D_FILE_OFFSET_BITS=64) + +## Targets ## +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../include" + "${CMAKE_CURRENT_BINARY_DIR}/../include") +link_directories("${CMAKE_CURRENT_BINARY_DIR}/../lib") +foreach(src suftest mksary sasearch bwt unbwt) + add_executable(${src} ${src}.c) + target_link_libraries(${src} divsufsort) +endforeach(src) diff --git a/tools/rasm/apultra-master/src/libdivsufsort/examples/bwt.c b/tools/rasm/apultra-master/src/libdivsufsort/examples/bwt.c new file mode 100644 index 0000000..5a362d0 --- /dev/null +++ b/tools/rasm/apultra-master/src/libdivsufsort/examples/bwt.c @@ -0,0 +1,220 @@ +/* + * bwt.c for libdivsufsort + * Copyright (c) 2003-2008 Yuta Mori 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. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include +#if HAVE_STRING_H +# include +#endif +#if HAVE_STDLIB_H +# include +#endif +#if HAVE_MEMORY_H +# include +#endif +#if HAVE_STDDEF_H +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_IO_H && HAVE_FCNTL_H +# include +# include +#endif +#include +#include +#include "lfs.h" + + +static +size_t +write_int(FILE *fp, saidx_t n) { + unsigned char c[4]; + c[0] = (unsigned char)((n >> 0) & 0xff), c[1] = (unsigned char)((n >> 8) & 0xff), + c[2] = (unsigned char)((n >> 16) & 0xff), c[3] = (unsigned char)((n >> 24) & 0xff); + return fwrite(c, sizeof(unsigned char), 4, fp); +} + +static +void +print_help(const char *progname, int status) { + fprintf(stderr, + "bwt, a burrows-wheeler transform program, version %s.\n", + divsufsort_version()); + fprintf(stderr, "usage: %s [-b num] INFILE OUTFILE\n", progname); + fprintf(stderr, " -b num set block size to num MiB [1..512] (default: 32)\n\n"); + exit(status); +} + +int +main(int argc, const char *argv[]) { + FILE *fp, *ofp; + const char *fname, *ofname; + sauchar_t *T; + saidx_t *SA; + LFS_OFF_T n; + size_t m; + saidx_t pidx; + clock_t start,finish; + saint_t i, blocksize = 32, needclose = 3; + + /* Check arguments. */ + if((argc == 1) || + (strcmp(argv[1], "-h") == 0) || + (strcmp(argv[1], "--help") == 0)) { print_help(argv[0], EXIT_SUCCESS); } + if((argc != 3) && (argc != 5)) { print_help(argv[0], EXIT_FAILURE); } + i = 1; + if(argc == 5) { + if(strcmp(argv[i], "-b") != 0) { print_help(argv[0], EXIT_FAILURE); } + blocksize = atoi(argv[i + 1]); + if(blocksize < 0) { blocksize = 1; } + else if(512 < blocksize) { blocksize = 512; } + i += 2; + } + blocksize <<= 20; + + /* Open a file for reading. */ + if(strcmp(argv[i], "-") != 0) { +#if HAVE_FOPEN_S + if(fopen_s(&fp, fname = argv[i], "rb") != 0) { +#else + if((fp = LFS_FOPEN(fname = argv[i], "rb")) == NULL) { +#endif + fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], fname); + perror(NULL); + exit(EXIT_FAILURE); + } + } else { +#if HAVE__SETMODE && HAVE__FILENO + if(_setmode(_fileno(stdin), _O_BINARY) == -1) { + fprintf(stderr, "%s: Cannot set mode: ", argv[0]); + perror(NULL); + exit(EXIT_FAILURE); + } +#endif + fp = stdin; + fname = "stdin"; + needclose ^= 1; + } + i += 1; + + /* Open a file for writing. */ + if(strcmp(argv[i], "-") != 0) { +#if HAVE_FOPEN_S + if(fopen_s(&ofp, ofname = argv[i], "wb") != 0) { +#else + if((ofp = LFS_FOPEN(ofname = argv[i], "wb")) == NULL) { +#endif + fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], ofname); + perror(NULL); + exit(EXIT_FAILURE); + } + } else { +#if HAVE__SETMODE && HAVE__FILENO + if(_setmode(_fileno(stdout), _O_BINARY) == -1) { + fprintf(stderr, "%s: Cannot set mode: ", argv[0]); + perror(NULL); + exit(EXIT_FAILURE); + } +#endif + ofp = stdout; + ofname = "stdout"; + needclose ^= 2; + } + + /* Get the file size. */ + if(LFS_FSEEK(fp, 0, SEEK_END) == 0) { + n = LFS_FTELL(fp); + rewind(fp); + if(n < 0) { + fprintf(stderr, "%s: Cannot ftell `%s': ", argv[0], fname); + perror(NULL); + exit(EXIT_FAILURE); + } + if(0x20000000L < n) { n = 0x20000000L; } + if((blocksize == 0) || (n < blocksize)) { blocksize = (saidx_t)n; } + } else if(blocksize == 0) { blocksize = 32 << 20; } + + /* Allocate 5blocksize bytes of memory. */ + T = (sauchar_t *)malloc(blocksize * sizeof(sauchar_t)); + SA = (saidx_t *)malloc(blocksize * sizeof(saidx_t)); + if((T == NULL) || (SA == NULL)) { + fprintf(stderr, "%s: Cannot allocate memory.\n", argv[0]); + exit(EXIT_FAILURE); + } + + /* Write the blocksize. */ + if(write_int(ofp, blocksize) != 4) { + fprintf(stderr, "%s: Cannot write to `%s': ", argv[0], ofname); + perror(NULL); + exit(EXIT_FAILURE); + } + + fprintf(stderr, " BWT (blocksize %" PRIdSAINT_T ") ... ", blocksize); + start = clock(); + for(n = 0; 0 < (m = fread(T, sizeof(sauchar_t), blocksize, fp)); n += m) { + /* Burrows-Wheeler Transform. */ + pidx = divbwt(T, T, SA, m); + if(pidx < 0) { + fprintf(stderr, "%s (bw_transform): %s.\n", + argv[0], + (pidx == -1) ? "Invalid arguments" : "Cannot allocate memory"); + exit(EXIT_FAILURE); + } + + /* Write the bwted data. */ + if((write_int(ofp, pidx) != 4) || + (fwrite(T, sizeof(sauchar_t), m, ofp) != m)) { + fprintf(stderr, "%s: Cannot write to `%s': ", argv[0], ofname); + perror(NULL); + exit(EXIT_FAILURE); + } + } + if(ferror(fp)) { + fprintf(stderr, "%s: Cannot read from `%s': ", argv[0], fname); + perror(NULL); + exit(EXIT_FAILURE); + } + finish = clock(); + fprintf(stderr, "%" PRIdOFF_T " bytes: %.4f sec\n", + n, (double)(finish - start) / (double)CLOCKS_PER_SEC); + + /* Close files */ + if(needclose & 1) { fclose(fp); } + if(needclose & 2) { fclose(ofp); } + + /* Deallocate memory. */ + free(SA); + free(T); + + return 0; +} diff --git a/tools/rasm/apultra-master/src/libdivsufsort/examples/mksary.c b/tools/rasm/apultra-master/src/libdivsufsort/examples/mksary.c new file mode 100644 index 0000000..b48177c --- /dev/null +++ b/tools/rasm/apultra-master/src/libdivsufsort/examples/mksary.c @@ -0,0 +1,193 @@ +/* + * mksary.c for libdivsufsort + * Copyright (c) 2003-2008 Yuta Mori 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. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include +#if HAVE_STRING_H +# include +#endif +#if HAVE_STDLIB_H +# include +#endif +#if HAVE_MEMORY_H +# include +#endif +#if HAVE_STDDEF_H +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_IO_H && HAVE_FCNTL_H +# include +# include +#endif +#include +#include +#include "lfs.h" + + +static +void +print_help(const char *progname, int status) { + fprintf(stderr, + "mksary, a simple suffix array builder, version %s.\n", + divsufsort_version()); + fprintf(stderr, "usage: %s INFILE OUTFILE\n\n", progname); + exit(status); +} + +int +main(int argc, const char *argv[]) { + FILE *fp, *ofp; + const char *fname, *ofname; + sauchar_t *T; + saidx_t *SA; + LFS_OFF_T n; + clock_t start, finish; + saint_t needclose = 3; + + /* Check arguments. */ + if((argc == 1) || + (strcmp(argv[1], "-h") == 0) || + (strcmp(argv[1], "--help") == 0)) { print_help(argv[0], EXIT_SUCCESS); } + if(argc != 3) { print_help(argv[0], EXIT_FAILURE); } + + /* Open a file for reading. */ + if(strcmp(argv[1], "-") != 0) { +#if HAVE_FOPEN_S + if(fopen_s(&fp, fname = argv[1], "rb") != 0) { +#else + if((fp = LFS_FOPEN(fname = argv[1], "rb")) == NULL) { +#endif + fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], fname); + perror(NULL); + exit(EXIT_FAILURE); + } + } else { +#if HAVE__SETMODE && HAVE__FILENO + if(_setmode(_fileno(stdin), _O_BINARY) == -1) { + fprintf(stderr, "%s: Cannot set mode: ", argv[0]); + perror(NULL); + exit(EXIT_FAILURE); + } +#endif + fp = stdin; + fname = "stdin"; + needclose ^= 1; + } + + /* Open a file for writing. */ + if(strcmp(argv[2], "-") != 0) { +#if HAVE_FOPEN_S + if(fopen_s(&ofp, ofname = argv[2], "wb") != 0) { +#else + if((ofp = LFS_FOPEN(ofname = argv[2], "wb")) == NULL) { +#endif + fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], ofname); + perror(NULL); + exit(EXIT_FAILURE); + } + } else { +#if HAVE__SETMODE && HAVE__FILENO + if(_setmode(_fileno(stdout), _O_BINARY) == -1) { + fprintf(stderr, "%s: Cannot set mode: ", argv[0]); + perror(NULL); + exit(EXIT_FAILURE); + } +#endif + ofp = stdout; + ofname = "stdout"; + needclose ^= 2; + } + + /* Get the file size. */ + if(LFS_FSEEK(fp, 0, SEEK_END) == 0) { + n = LFS_FTELL(fp); + rewind(fp); + if(n < 0) { + fprintf(stderr, "%s: Cannot ftell `%s': ", argv[0], fname); + perror(NULL); + exit(EXIT_FAILURE); + } + if(0x7fffffff <= n) { + fprintf(stderr, "%s: Input file `%s' is too big.\n", argv[0], fname); + exit(EXIT_FAILURE); + } + } else { + fprintf(stderr, "%s: Cannot fseek `%s': ", argv[0], fname); + perror(NULL); + exit(EXIT_FAILURE); + } + + /* Allocate 5blocksize bytes of memory. */ + T = (sauchar_t *)malloc((size_t)n * sizeof(sauchar_t)); + SA = (saidx_t *)malloc((size_t)n * sizeof(saidx_t)); + if((T == NULL) || (SA == NULL)) { + fprintf(stderr, "%s: Cannot allocate memory.\n", argv[0]); + exit(EXIT_FAILURE); + } + + /* Read n bytes of data. */ + if(fread(T, sizeof(sauchar_t), (size_t)n, fp) != (size_t)n) { + fprintf(stderr, "%s: %s `%s': ", + argv[0], + (ferror(fp) || !feof(fp)) ? "Cannot read from" : "Unexpected EOF in", + fname); + perror(NULL); + exit(EXIT_FAILURE); + } + if(needclose & 1) { fclose(fp); } + + /* Construct the suffix array. */ + fprintf(stderr, "%s: %" PRIdOFF_T " bytes ... ", fname, n); + start = clock(); + if(divsufsort(T, SA, (saidx_t)n) != 0) { + fprintf(stderr, "%s: Cannot allocate memory.\n", argv[0]); + exit(EXIT_FAILURE); + } + finish = clock(); + fprintf(stderr, "%.4f sec\n", (double)(finish - start) / (double)CLOCKS_PER_SEC); + + /* Write the suffix array. */ + if(fwrite(SA, sizeof(saidx_t), (size_t)n, ofp) != (size_t)n) { + fprintf(stderr, "%s: Cannot write to `%s': ", argv[0], ofname); + perror(NULL); + exit(EXIT_FAILURE); + } + if(needclose & 2) { fclose(ofp); } + + /* Deallocate memory. */ + free(SA); + free(T); + + return 0; +} diff --git a/tools/rasm/apultra-master/src/libdivsufsort/examples/sasearch.c b/tools/rasm/apultra-master/src/libdivsufsort/examples/sasearch.c new file mode 100644 index 0000000..7e5ca4f --- /dev/null +++ b/tools/rasm/apultra-master/src/libdivsufsort/examples/sasearch.c @@ -0,0 +1,165 @@ +/* + * sasearch.c for libdivsufsort + * Copyright (c) 2003-2008 Yuta Mori 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. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include +#if HAVE_STRING_H +# include +#endif +#if HAVE_STDLIB_H +# include +#endif +#if HAVE_MEMORY_H +# include +#endif +#if HAVE_STDDEF_H +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_IO_H && HAVE_FCNTL_H +# include +# include +#endif +#include +#include "lfs.h" + + +static +void +print_help(const char *progname, int status) { + fprintf(stderr, + "sasearch, a simple SA-based full-text search tool, version %s\n", + divsufsort_version()); + fprintf(stderr, "usage: %s PATTERN FILE SAFILE\n\n", progname); + exit(status); +} + +int +main(int argc, const char *argv[]) { + FILE *fp; + const char *P; + sauchar_t *T; + saidx_t *SA; + LFS_OFF_T n; + size_t Psize; + saidx_t i, size, left; + + if((argc == 1) || + (strcmp(argv[1], "-h") == 0) || + (strcmp(argv[1], "--help") == 0)) { print_help(argv[0], EXIT_SUCCESS); } + if(argc != 4) { print_help(argv[0], EXIT_FAILURE); } + + P = argv[1]; + Psize = strlen(P); + + /* Open a file for reading. */ +#if HAVE_FOPEN_S + if(fopen_s(&fp, argv[2], "rb") != 0) { +#else + if((fp = LFS_FOPEN(argv[2], "rb")) == NULL) { +#endif + fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], argv[2]); + perror(NULL); + exit(EXIT_FAILURE); + } + + /* Get the file size. */ + if(LFS_FSEEK(fp, 0, SEEK_END) == 0) { + n = LFS_FTELL(fp); + rewind(fp); + if(n < 0) { + fprintf(stderr, "%s: Cannot ftell `%s': ", argv[0], argv[2]); + perror(NULL); + exit(EXIT_FAILURE); + } + } else { + fprintf(stderr, "%s: Cannot fseek `%s': ", argv[0], argv[2]); + perror(NULL); + exit(EXIT_FAILURE); + } + + /* Allocate 5n bytes of memory. */ + T = (sauchar_t *)malloc((size_t)n * sizeof(sauchar_t)); + SA = (saidx_t *)malloc((size_t)n * sizeof(saidx_t)); + if((T == NULL) || (SA == NULL)) { + fprintf(stderr, "%s: Cannot allocate memory.\n", argv[0]); + exit(EXIT_FAILURE); + } + + /* Read n bytes of data. */ + if(fread(T, sizeof(sauchar_t), (size_t)n, fp) != (size_t)n) { + fprintf(stderr, "%s: %s `%s': ", + argv[0], + (ferror(fp) || !feof(fp)) ? "Cannot read from" : "Unexpected EOF in", + argv[2]); + perror(NULL); + exit(EXIT_FAILURE); + } + fclose(fp); + + /* Open the SA file for reading. */ +#if HAVE_FOPEN_S + if(fopen_s(&fp, argv[3], "rb") != 0) { +#else + if((fp = LFS_FOPEN(argv[3], "rb")) == NULL) { +#endif + fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], argv[3]); + perror(NULL); + exit(EXIT_FAILURE); + } + + /* Read n * sizeof(saidx_t) bytes of data. */ + if(fread(SA, sizeof(saidx_t), (size_t)n, fp) != (size_t)n) { + fprintf(stderr, "%s: %s `%s': ", + argv[0], + (ferror(fp) || !feof(fp)) ? "Cannot read from" : "Unexpected EOF in", + argv[3]); + perror(NULL); + exit(EXIT_FAILURE); + } + fclose(fp); + + /* Search and print */ + size = sa_search(T, (saidx_t)n, + (const sauchar_t *)P, (saidx_t)Psize, + SA, (saidx_t)n, &left); + for(i = 0; i < size; ++i) { + fprintf(stdout, "%" PRIdSAIDX_T "\n", SA[left + i]); + } + + /* Deallocate memory. */ + free(SA); + free(T); + + return 0; +} diff --git a/tools/rasm/apultra-master/src/libdivsufsort/examples/suftest.c b/tools/rasm/apultra-master/src/libdivsufsort/examples/suftest.c new file mode 100644 index 0000000..71892ac --- /dev/null +++ b/tools/rasm/apultra-master/src/libdivsufsort/examples/suftest.c @@ -0,0 +1,164 @@ +/* + * suftest.c for libdivsufsort + * Copyright (c) 2003-2008 Yuta Mori 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. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include +#if HAVE_STRING_H +# include +#endif +#if HAVE_STDLIB_H +# include +#endif +#if HAVE_MEMORY_H +# include +#endif +#if HAVE_STDDEF_H +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_IO_H && HAVE_FCNTL_H +# include +# include +#endif +#include +#include +#include "lfs.h" + + +static +void +print_help(const char *progname, int status) { + fprintf(stderr, + "suftest, a suffixsort tester, version %s.\n", + divsufsort_version()); + fprintf(stderr, "usage: %s FILE\n\n", progname); + exit(status); +} + +int +main(int argc, const char *argv[]) { + FILE *fp; + const char *fname; + sauchar_t *T; + saidx_t *SA; + LFS_OFF_T n; + clock_t start, finish; + saint_t needclose = 1; + + /* Check arguments. */ + if((argc == 1) || + (strcmp(argv[1], "-h") == 0) || + (strcmp(argv[1], "--help") == 0)) { print_help(argv[0], EXIT_SUCCESS); } + if(argc != 2) { print_help(argv[0], EXIT_FAILURE); } + + /* Open a file for reading. */ + if(strcmp(argv[1], "-") != 0) { +#if HAVE_FOPEN_S + if(fopen_s(&fp, fname = argv[1], "rb") != 0) { +#else + if((fp = LFS_FOPEN(fname = argv[1], "rb")) == NULL) { +#endif + fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], fname); + perror(NULL); + exit(EXIT_FAILURE); + } + } else { +#if HAVE__SETMODE && HAVE__FILENO + if(_setmode(_fileno(stdin), _O_BINARY) == -1) { + fprintf(stderr, "%s: Cannot set mode: ", argv[0]); + perror(NULL); + exit(EXIT_FAILURE); + } +#endif + fp = stdin; + fname = "stdin"; + needclose = 0; + } + + /* Get the file size. */ + if(LFS_FSEEK(fp, 0, SEEK_END) == 0) { + n = LFS_FTELL(fp); + rewind(fp); + if(n < 0) { + fprintf(stderr, "%s: Cannot ftell `%s': ", argv[0], fname); + perror(NULL); + exit(EXIT_FAILURE); + } + if(0x7fffffff <= n) { + fprintf(stderr, "%s: Input file `%s' is too big.\n", argv[0], fname); + exit(EXIT_FAILURE); + } + } else { + fprintf(stderr, "%s: Cannot fseek `%s': ", argv[0], fname); + perror(NULL); + exit(EXIT_FAILURE); + } + + /* Allocate 5n bytes of memory. */ + T = (sauchar_t *)malloc((size_t)n * sizeof(sauchar_t)); + SA = (saidx_t *)malloc((size_t)n * sizeof(saidx_t)); + if((T == NULL) || (SA == NULL)) { + fprintf(stderr, "%s: Cannot allocate memory.\n", argv[0]); + exit(EXIT_FAILURE); + } + + /* Read n bytes of data. */ + if(fread(T, sizeof(sauchar_t), (size_t)n, fp) != (size_t)n) { + fprintf(stderr, "%s: %s `%s': ", + argv[0], + (ferror(fp) || !feof(fp)) ? "Cannot read from" : "Unexpected EOF in", + argv[1]); + perror(NULL); + exit(EXIT_FAILURE); + } + if(needclose & 1) { fclose(fp); } + + /* Construct the suffix array. */ + fprintf(stderr, "%s: %" PRIdOFF_T " bytes ... ", fname, n); + start = clock(); + if(divsufsort(T, SA, (saidx_t)n) != 0) { + fprintf(stderr, "%s: Cannot allocate memory.\n", argv[0]); + exit(EXIT_FAILURE); + } + finish = clock(); + fprintf(stderr, "%.4f sec\n", (double)(finish - start) / (double)CLOCKS_PER_SEC); + + /* Check the suffix array. */ + if(sufcheck(T, SA, (saidx_t)n, 1) != 0) { exit(EXIT_FAILURE); } + + /* Deallocate memory. */ + free(SA); + free(T); + + return 0; +} diff --git a/tools/rasm/apultra-master/src/libdivsufsort/examples/unbwt.c b/tools/rasm/apultra-master/src/libdivsufsort/examples/unbwt.c new file mode 100644 index 0000000..c0f19e9 --- /dev/null +++ b/tools/rasm/apultra-master/src/libdivsufsort/examples/unbwt.c @@ -0,0 +1,207 @@ +/* + * unbwt.c for libdivsufsort + * Copyright (c) 2003-2008 Yuta Mori 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. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include +#if HAVE_STRING_H +# include +#endif +#if HAVE_STDLIB_H +# include +#endif +#if HAVE_MEMORY_H +# include +#endif +#if HAVE_STDDEF_H +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_IO_H && HAVE_FCNTL_H +# include +# include +#endif +#include +#include +#include "lfs.h" + + +static +size_t +read_int(FILE *fp, saidx_t *n) { + unsigned char c[4]; + size_t m = fread(c, sizeof(unsigned char), 4, fp); + if(m == 4) { + *n = (c[0] << 0) | (c[1] << 8) | + (c[2] << 16) | (c[3] << 24); + } + return m; +} + +static +void +print_help(const char *progname, int status) { + fprintf(stderr, + "unbwt, an inverse burrows-wheeler transform program, version %s.\n", + divsufsort_version()); + fprintf(stderr, "usage: %s INFILE OUTFILE\n\n", progname); + exit(status); +} + +int +main(int argc, const char *argv[]) { + FILE *fp, *ofp; + const char *fname, *ofname; + sauchar_t *T; + saidx_t *A; + LFS_OFF_T n; + size_t m; + saidx_t pidx; + clock_t start, finish; + saint_t err, blocksize, needclose = 3; + + /* Check arguments. */ + if((argc == 1) || + (strcmp(argv[1], "-h") == 0) || + (strcmp(argv[1], "--help") == 0)) { print_help(argv[0], EXIT_SUCCESS); } + if(argc != 3) { print_help(argv[0], EXIT_FAILURE); } + + /* Open a file for reading. */ + if(strcmp(argv[1], "-") != 0) { +#if HAVE_FOPEN_S + if(fopen_s(&fp, fname = argv[1], "rb") != 0) { +#else + if((fp = LFS_FOPEN(fname = argv[1], "rb")) == NULL) { +#endif + fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], fname); + perror(NULL); + exit(EXIT_FAILURE); + } + } else { +#if HAVE__SETMODE && HAVE__FILENO + if(_setmode(_fileno(stdin), _O_BINARY) == -1) { + fprintf(stderr, "%s: Cannot set mode: ", argv[0]); + perror(NULL); + exit(EXIT_FAILURE); + } +#endif + fp = stdin; + fname = "stdin"; + needclose ^= 1; + } + + /* Open a file for writing. */ + if(strcmp(argv[2], "-") != 0) { +#if HAVE_FOPEN_S + if(fopen_s(&ofp, ofname = argv[2], "wb") != 0) { +#else + if((ofp = LFS_FOPEN(ofname = argv[2], "wb")) == NULL) { +#endif + fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], ofname); + perror(NULL); + exit(EXIT_FAILURE); + } + } else { +#if HAVE__SETMODE && HAVE__FILENO + if(_setmode(_fileno(stdout), _O_BINARY) == -1) { + fprintf(stderr, "%s: Cannot set mode: ", argv[0]); + perror(NULL); + exit(EXIT_FAILURE); + } +#endif + ofp = stdout; + ofname = "stdout"; + needclose ^= 2; + } + + /* Read the blocksize. */ + if(read_int(fp, &blocksize) != 4) { + fprintf(stderr, "%s: Cannot read from `%s': ", argv[0], fname); + perror(NULL); + exit(EXIT_FAILURE); + } + + /* Allocate 5blocksize bytes of memory. */ + T = (sauchar_t *)malloc(blocksize * sizeof(sauchar_t)); + A = (saidx_t *)malloc(blocksize * sizeof(saidx_t)); + if((T == NULL) || (A == NULL)) { + fprintf(stderr, "%s: Cannot allocate memory.\n", argv[0]); + exit(EXIT_FAILURE); + } + + fprintf(stderr, "UnBWT (blocksize %" PRIdSAINT_T ") ... ", blocksize); + start = clock(); + for(n = 0; (m = read_int(fp, &pidx)) != 0; n += m) { + /* Read blocksize bytes of data. */ + if((m != 4) || ((m = fread(T, sizeof(sauchar_t), blocksize, fp)) == 0)) { + fprintf(stderr, "%s: %s `%s': ", + argv[0], + (ferror(fp) || !feof(fp)) ? "Cannot read from" : "Unexpected EOF in", + fname); + perror(NULL); + exit(EXIT_FAILURE); + } + + /* Inverse Burrows-Wheeler Transform. */ + if((err = inverse_bw_transform(T, T, A, m, pidx)) != 0) { + fprintf(stderr, "%s (reverseBWT): %s.\n", + argv[0], + (err == -1) ? "Invalid data" : "Cannot allocate memory"); + exit(EXIT_FAILURE); + } + + /* Write m bytes of data. */ + if(fwrite(T, sizeof(sauchar_t), m, ofp) != m) { + fprintf(stderr, "%s: Cannot write to `%s': ", argv[0], ofname); + perror(NULL); + exit(EXIT_FAILURE); + } + } + if(ferror(fp)) { + fprintf(stderr, "%s: Cannot read from `%s': ", argv[0], fname); + perror(NULL); + exit(EXIT_FAILURE); + } + finish = clock(); + fprintf(stderr, "%" PRIdOFF_T " bytes: %.4f sec\n", + n, (double)(finish - start) / (double)CLOCKS_PER_SEC); + + /* Close files */ + if(needclose & 1) { fclose(fp); } + if(needclose & 2) { fclose(ofp); } + + /* Deallocate memory. */ + free(A); + free(T); + + return 0; +} diff --git a/tools/rasm/apultra-master/src/libdivsufsort/include/CMakeLists.txt b/tools/rasm/apultra-master/src/libdivsufsort/include/CMakeLists.txt new file mode 100644 index 0000000..37781cc --- /dev/null +++ b/tools/rasm/apultra-master/src/libdivsufsort/include/CMakeLists.txt @@ -0,0 +1,162 @@ +include(CheckIncludeFiles) +include(CheckIncludeFile) +include(CheckSymbolExists) +include(CheckTypeSize) +include(CheckFunctionKeywords) +include(CheckLFS) + +## Checks for header files ## +check_include_file("inttypes.h" HAVE_INTTYPES_H) +check_include_file("memory.h" HAVE_MEMORY_H) +check_include_file("stddef.h" HAVE_STDDEF_H) +check_include_file("stdint.h" HAVE_STDINT_H) +check_include_file("stdlib.h" HAVE_STDLIB_H) +check_include_file("string.h" HAVE_STRING_H) +check_include_file("strings.h" HAVE_STRINGS_H) +check_include_file("sys/types.h" HAVE_SYS_TYPES_H) +if(HAVE_INTTYPES_H) + set(INCFILE "#include ") +elseif(HAVE_STDINT_H) + set(INCFILE "#include ") +else(HAVE_INTTYPES_H) + set(INCFILE "") +endif(HAVE_INTTYPES_H) + +## create configuration files from .cmake file ## +if(BUILD_EXAMPLES) + ## Checks for WinIO ## + if(WIN32) + check_include_file("io.h" HAVE_IO_H) + check_include_file("fcntl.h" HAVE_FCNTL_H) + check_symbol_exists("_setmode" "io.h;fcntl.h" HAVE__SETMODE) + if(NOT HAVE__SETMODE) + check_symbol_exists("setmode" "io.h;fcntl.h" HAVE_SETMODE) + endif(NOT HAVE__SETMODE) + check_symbol_exists("_fileno" "stdio.h" HAVE__FILENO) + check_symbol_exists("fopen_s" "stdio.h" HAVE_FOPEN_S) + check_symbol_exists("_O_BINARY" "fcntl.h" HAVE__O_BINARY) + endif(WIN32) + + ## Checks for large file support ## + check_lfs(WITH_LFS) + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/lfs.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/lfs.h" @ONLY) +endif(BUILD_EXAMPLES) + +## generate config.h ## +check_function_keywords("inline;__inline;__inline__;__declspec(dllexport);__declspec(dllimport)") +if(HAVE_INLINE) + set(INLINE "inline") +elseif(HAVE___INLINE) + set(INLINE "__inline") +elseif(HAVE___INLINE__) + set(INLINE "__inline__") +else(HAVE_INLINE) + set(INLINE "") +endif(HAVE_INLINE) +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/config.h") + +## Checks for types ## +# sauchar_t (8bit) +check_type_size("uint8_t" UINT8_T) +if(HAVE_UINT8_T) + set(SAUCHAR_TYPE "uint8_t") +else(HAVE_UINT8_T) + check_type_size("unsigned char" SIZEOF_UNSIGNED_CHAR) + if("${SIZEOF_UNSIGNED_CHAR}" STREQUAL "1") + set(SAUCHAR_TYPE "unsigned char") + else("${SIZEOF_UNSIGNED_CHAR}" STREQUAL "1") + message(FATAL_ERROR "Cannot find unsigned 8-bit integer type") + endif("${SIZEOF_UNSIGNED_CHAR}" STREQUAL "1") +endif(HAVE_UINT8_T) +# saint_t (32bit) +check_type_size("int32_t" INT32_T) +if(HAVE_INT32_T) + set(SAINT32_TYPE "int32_t") + check_symbol_exists("PRId32" "inttypes.h" HAVE_PRID32) + if(HAVE_PRID32) + set(SAINT32_PRId "PRId32") + else(HAVE_PRID32) + set(SAINT32_PRId "\"d\"") + endif(HAVE_PRID32) +else(HAVE_INT32_T) + check_type_size("int" SIZEOF_INT) + check_type_size("long" SIZEOF_LONG) + check_type_size("short" SIZEOF_SHORT) + check_type_size("__int32" SIZEOF___INT32) + if("${SIZEOF_INT}" STREQUAL "4") + set(SAINT32_TYPE "int") + set(SAINT32_PRId "\"d\"") + elseif("${SIZEOF_LONG}" STREQUAL "4") + set(SAINT32_TYPE "long") + set(SAINT32_PRId "\"ld\"") + elseif("${SIZEOF_SHORT}" STREQUAL "4") + set(SAINT32_TYPE "short") + set(SAINT32_PRId "\"d\"") + elseif("${SIZEOF___INT32}" STREQUAL "4") + set(SAINT32_TYPE "__int32") + set(SAINT32_PRId "\"d\"") + else("${SIZEOF_INT}" STREQUAL "4") + message(FATAL_ERROR "Cannot find 32-bit integer type") + endif("${SIZEOF_INT}" STREQUAL "4") +endif(HAVE_INT32_T) +# saint64_t (64bit) +if(BUILD_DIVSUFSORT64) + check_type_size("int64_t" INT64_T) + if(HAVE_INT64_T) + set(SAINT64_TYPE "int64_t") + check_symbol_exists("PRId64" "inttypes.h" HAVE_PRID64) + if(HAVE_PRID64) + set(SAINT64_PRId "PRId64") + else(HAVE_PRID64) + set(SAINT64_PRId "\"lld\"") + endif(HAVE_PRID64) + else(HAVE_INT64_T) + check_type_size("int" SIZEOF_INT) + check_type_size("long" SIZEOF_LONG) + check_type_size("long long" SIZEOF_LONG_LONG) + check_type_size("__int64" SIZEOF___INT64) + if("${SIZEOF_INT}" STREQUAL "8") + set(SAINT64_TYPE "int") + set(SAINT64_PRId "\"d\"") + elseif("${SIZEOF_LONG}" STREQUAL "8") + set(SAINT64_TYPE "long") + set(SAINT64_PRId "\"ld\"") + elseif("${SIZEOF_LONG_LONG}" STREQUAL "8") + set(SAINT64_TYPE "long long") + set(SAINT64_PRId "\"lld\"") + elseif("${SIZEOF___INT64}" STREQUAL "8") + set(SAINT64_TYPE "__int64") + set(SAINT64_PRId "\"I64d\"") + else("${SIZEOF_INT}" STREQUAL "8") + message(SEND_ERROR "Cannot find 64-bit integer type") + set(BUILD_DIVSUFSORT64 OFF) + endif("${SIZEOF_INT}" STREQUAL "8") + endif(HAVE_INT64_T) +endif(BUILD_DIVSUFSORT64) + +## generate divsufsort.h ## +set(DIVSUFSORT_IMPORT "") +set(DIVSUFSORT_EXPORT "") +if(BUILD_SHARED_LIBS) + if(HAVE___DECLSPEC_DLLIMPORT_) + set(DIVSUFSORT_IMPORT "__declspec(dllimport)") + endif(HAVE___DECLSPEC_DLLIMPORT_) + if(HAVE___DECLSPEC_DLLEXPORT_) + set(DIVSUFSORT_EXPORT "__declspec(dllexport)") + endif(HAVE___DECLSPEC_DLLEXPORT_) +endif(BUILD_SHARED_LIBS) +set(W64BIT "") +set(SAINDEX_TYPE "${SAINT32_TYPE}") +set(SAINDEX_PRId "${SAINT32_PRId}") +set(SAINT_PRId "${SAINT32_PRId}") +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/divsufsort.h.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/divsufsort.h" @ONLY) +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/divsufsort.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +if(BUILD_DIVSUFSORT64) + set(W64BIT "64") + set(SAINDEX_TYPE "${SAINT64_TYPE}") + set(SAINDEX_PRId "${SAINT64_PRId}") + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/divsufsort.h.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/divsufsort64.h" @ONLY) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/divsufsort64.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +endif(BUILD_DIVSUFSORT64) diff --git a/tools/rasm/apultra-master/src/libdivsufsort/include/config.h.cmake b/tools/rasm/apultra-master/src/libdivsufsort/include/config.h.cmake new file mode 100644 index 0000000..6a1cf47 --- /dev/null +++ b/tools/rasm/apultra-master/src/libdivsufsort/include/config.h.cmake @@ -0,0 +1,81 @@ +/* + * config.h for libdivsufsort + * Copyright (c) 2003-2008 Yuta Mori 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 _CONFIG_H +#define _CONFIG_H 1 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** Define to the version of this package. **/ +#cmakedefine PROJECT_VERSION_FULL "${PROJECT_VERSION_FULL}" + +/** Define to 1 if you have the header files. **/ +#cmakedefine HAVE_INTTYPES_H 1 +#cmakedefine HAVE_STDDEF_H 1 +#cmakedefine HAVE_STDINT_H 1 +#cmakedefine HAVE_STDLIB_H 1 +#cmakedefine HAVE_STRING_H 1 +#cmakedefine HAVE_STRINGS_H 1 +#cmakedefine HAVE_MEMORY_H 1 +#cmakedefine HAVE_SYS_TYPES_H 1 + +/** for WinIO **/ +#cmakedefine HAVE_IO_H 1 +#cmakedefine HAVE_FCNTL_H 1 +#cmakedefine HAVE__SETMODE 1 +#cmakedefine HAVE_SETMODE 1 +#cmakedefine HAVE__FILENO 1 +#cmakedefine HAVE_FOPEN_S 1 +#cmakedefine HAVE__O_BINARY 1 +#ifndef HAVE__SETMODE +# if HAVE_SETMODE +# define _setmode setmode +# define HAVE__SETMODE 1 +# endif +# if HAVE__SETMODE && !HAVE__O_BINARY +# define _O_BINARY 0 +# define HAVE__O_BINARY 1 +# endif +#endif + +/** for inline **/ +#ifndef INLINE +# define INLINE @INLINE@ +#endif + +/** for VC++ warning **/ +#ifdef _MSC_VER +#pragma warning(disable: 4127) +#endif + + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* _CONFIG_H */ diff --git a/tools/rasm/apultra-master/src/libdivsufsort/include/divsufsort.h b/tools/rasm/apultra-master/src/libdivsufsort/include/divsufsort.h new file mode 100644 index 0000000..7ebb412 --- /dev/null +++ b/tools/rasm/apultra-master/src/libdivsufsort/include/divsufsort.h @@ -0,0 +1,189 @@ +/* + * divsufsort.h for libdivsufsort + * Copyright (c) 2003-2008 Yuta Mori 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 _DIVSUFSORT_H +#define _DIVSUFSORT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define DIVSUFSORT_API + +/*- Datatypes -*/ +#ifndef SAUCHAR_T +#define SAUCHAR_T +typedef unsigned char sauchar_t; +#endif /* SAUCHAR_T */ +#ifndef SAINT_T +#define SAINT_T +typedef int saint_t; +#endif /* SAINT_T */ +#ifndef SAIDX_T +#define SAIDX_T +typedef int saidx_t; +#endif /* SAIDX_T */ +#ifndef PRIdSAIDX_T +#define PRIdSAIDX_T "d" +#endif + +/*- divsufsort context */ +typedef struct _divsufsort_ctx_t { + saidx_t *bucket_A; + saidx_t *bucket_B; +} divsufsort_ctx_t; + +/*- Prototypes -*/ + +/** + * Initialize suffix array context + * + * @return 0 for success, or non-zero in case of an error + */ +int divsufsort_init(divsufsort_ctx_t *ctx); + +/** + * Destroy suffix array context + * + * @param ctx suffix array context to destroy + */ +void divsufsort_destroy(divsufsort_ctx_t *ctx); + +/** + * Constructs the suffix array of a given string. + * @param ctx suffix array context + * @param T[0..n-1] The input string. + * @param SA[0..n-1] The output array of suffixes. + * @param n The length of the given string. + * @return 0 if no error occurred, -1 or -2 otherwise. + */ +DIVSUFSORT_API +saint_t divsufsort_build_array(divsufsort_ctx_t *ctx, const sauchar_t *T, saidx_t *SA, saidx_t n); + +#if 0 +/** + * Constructs the burrows-wheeler transformed string of a given string. + * @param T[0..n-1] The input string. + * @param U[0..n-1] The output string. (can be T) + * @param A[0..n-1] The temporary array. (can be NULL) + * @param n The length of the given string. + * @return The primary index if no error occurred, -1 or -2 otherwise. + */ +DIVSUFSORT_API +saidx_t +divbwt(const sauchar_t *T, sauchar_t *U, saidx_t *A, saidx_t n); + +/** + * Returns the version of the divsufsort library. + * @return The version number string. + */ +DIVSUFSORT_API +const char * +divsufsort_version(void); + + +/** + * Constructs the burrows-wheeler transformed string of a given string and suffix array. + * @param T[0..n-1] The input string. + * @param U[0..n-1] The output string. (can be T) + * @param SA[0..n-1] The suffix array. (can be NULL) + * @param n The length of the given string. + * @param idx The output primary index. + * @return 0 if no error occurred, -1 or -2 otherwise. + */ +DIVSUFSORT_API +saint_t +bw_transform(const sauchar_t *T, sauchar_t *U, + saidx_t *SA /* can NULL */, + saidx_t n, saidx_t *idx); + +/** + * Inverse BW-transforms a given BWTed string. + * @param T[0..n-1] The input string. + * @param U[0..n-1] The output string. (can be T) + * @param A[0..n-1] The temporary array. (can be NULL) + * @param n The length of the given string. + * @param idx The primary index. + * @return 0 if no error occurred, -1 or -2 otherwise. + */ +DIVSUFSORT_API +saint_t +inverse_bw_transform(const sauchar_t *T, sauchar_t *U, + saidx_t *A /* can NULL */, + saidx_t n, saidx_t idx); + +/** + * Checks the correctness of a given suffix array. + * @param T[0..n-1] The input string. + * @param SA[0..n-1] The input suffix array. + * @param n The length of the given string. + * @param verbose The verbose mode. + * @return 0 if no error occurred. + */ +DIVSUFSORT_API +saint_t +sufcheck(const sauchar_t *T, const saidx_t *SA, saidx_t n, saint_t verbose); + +/** + * Search for the pattern P in the string T. + * @param T[0..Tsize-1] The input string. + * @param Tsize The length of the given string. + * @param P[0..Psize-1] The input pattern string. + * @param Psize The length of the given pattern string. + * @param SA[0..SAsize-1] The input suffix array. + * @param SAsize The length of the given suffix array. + * @param idx The output index. + * @return The count of matches if no error occurred, -1 otherwise. + */ +DIVSUFSORT_API +saidx_t +sa_search(const sauchar_t *T, saidx_t Tsize, + const sauchar_t *P, saidx_t Psize, + const saidx_t *SA, saidx_t SAsize, + saidx_t *left); + +/** + * Search for the character c in the string T. + * @param T[0..Tsize-1] The input string. + * @param Tsize The length of the given string. + * @param SA[0..SAsize-1] The input suffix array. + * @param SAsize The length of the given suffix array. + * @param c The input character. + * @param idx The output index. + * @return The count of matches if no error occurred, -1 otherwise. + */ +DIVSUFSORT_API +saidx_t +sa_simplesearch(const sauchar_t *T, saidx_t Tsize, + const saidx_t *SA, saidx_t SAsize, + saint_t c, saidx_t *left); +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* _DIVSUFSORT_H */ diff --git a/tools/rasm/apultra-master/src/libdivsufsort/include/divsufsort.h.cmake b/tools/rasm/apultra-master/src/libdivsufsort/include/divsufsort.h.cmake new file mode 100644 index 0000000..bcaba7c --- /dev/null +++ b/tools/rasm/apultra-master/src/libdivsufsort/include/divsufsort.h.cmake @@ -0,0 +1,180 @@ +/* + * divsufsort@W64BIT@.h for libdivsufsort@W64BIT@ + * Copyright (c) 2003-2008 Yuta Mori 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 _DIVSUFSORT@W64BIT@_H +#define _DIVSUFSORT@W64BIT@_H 1 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +@INCFILE@ + +#ifndef DIVSUFSORT_API +# ifdef DIVSUFSORT_BUILD_DLL +# define DIVSUFSORT_API @DIVSUFSORT_EXPORT@ +# else +# define DIVSUFSORT_API @DIVSUFSORT_IMPORT@ +# endif +#endif + +/*- Datatypes -*/ +#ifndef SAUCHAR_T +#define SAUCHAR_T +typedef @SAUCHAR_TYPE@ sauchar_t; +#endif /* SAUCHAR_T */ +#ifndef SAINT_T +#define SAINT_T +typedef @SAINT32_TYPE@ saint_t; +#endif /* SAINT_T */ +#ifndef SAIDX@W64BIT@_T +#define SAIDX@W64BIT@_T +typedef @SAINDEX_TYPE@ saidx@W64BIT@_t; +#endif /* SAIDX@W64BIT@_T */ +#ifndef PRIdSAINT_T +#define PRIdSAINT_T @SAINT_PRId@ +#endif /* PRIdSAINT_T */ +#ifndef PRIdSAIDX@W64BIT@_T +#define PRIdSAIDX@W64BIT@_T @SAINDEX_PRId@ +#endif /* PRIdSAIDX@W64BIT@_T */ + + +/*- Prototypes -*/ + +/** + * Constructs the suffix array of a given string. + * @param T[0..n-1] The input string. + * @param SA[0..n-1] The output array of suffixes. + * @param n The length of the given string. + * @return 0 if no error occurred, -1 or -2 otherwise. + */ +DIVSUFSORT_API +saint_t +divsufsort@W64BIT@(const sauchar_t *T, saidx@W64BIT@_t *SA, saidx@W64BIT@_t n); + +/** + * Constructs the burrows-wheeler transformed string of a given string. + * @param T[0..n-1] The input string. + * @param U[0..n-1] The output string. (can be T) + * @param A[0..n-1] The temporary array. (can be NULL) + * @param n The length of the given string. + * @return The primary index if no error occurred, -1 or -2 otherwise. + */ +DIVSUFSORT_API +saidx@W64BIT@_t +divbwt@W64BIT@(const sauchar_t *T, sauchar_t *U, saidx@W64BIT@_t *A, saidx@W64BIT@_t n); + +/** + * Returns the version of the divsufsort library. + * @return The version number string. + */ +DIVSUFSORT_API +const char * +divsufsort@W64BIT@_version(void); + + +/** + * Constructs the burrows-wheeler transformed string of a given string and suffix array. + * @param T[0..n-1] The input string. + * @param U[0..n-1] The output string. (can be T) + * @param SA[0..n-1] The suffix array. (can be NULL) + * @param n The length of the given string. + * @param idx The output primary index. + * @return 0 if no error occurred, -1 or -2 otherwise. + */ +DIVSUFSORT_API +saint_t +bw_transform@W64BIT@(const sauchar_t *T, sauchar_t *U, + saidx@W64BIT@_t *SA /* can NULL */, + saidx@W64BIT@_t n, saidx@W64BIT@_t *idx); + +/** + * Inverse BW-transforms a given BWTed string. + * @param T[0..n-1] The input string. + * @param U[0..n-1] The output string. (can be T) + * @param A[0..n-1] The temporary array. (can be NULL) + * @param n The length of the given string. + * @param idx The primary index. + * @return 0 if no error occurred, -1 or -2 otherwise. + */ +DIVSUFSORT_API +saint_t +inverse_bw_transform@W64BIT@(const sauchar_t *T, sauchar_t *U, + saidx@W64BIT@_t *A /* can NULL */, + saidx@W64BIT@_t n, saidx@W64BIT@_t idx); + +/** + * Checks the correctness of a given suffix array. + * @param T[0..n-1] The input string. + * @param SA[0..n-1] The input suffix array. + * @param n The length of the given string. + * @param verbose The verbose mode. + * @return 0 if no error occurred. + */ +DIVSUFSORT_API +saint_t +sufcheck@W64BIT@(const sauchar_t *T, const saidx@W64BIT@_t *SA, saidx@W64BIT@_t n, saint_t verbose); + +/** + * Search for the pattern P in the string T. + * @param T[0..Tsize-1] The input string. + * @param Tsize The length of the given string. + * @param P[0..Psize-1] The input pattern string. + * @param Psize The length of the given pattern string. + * @param SA[0..SAsize-1] The input suffix array. + * @param SAsize The length of the given suffix array. + * @param idx The output index. + * @return The count of matches if no error occurred, -1 otherwise. + */ +DIVSUFSORT_API +saidx@W64BIT@_t +sa_search@W64BIT@(const sauchar_t *T, saidx@W64BIT@_t Tsize, + const sauchar_t *P, saidx@W64BIT@_t Psize, + const saidx@W64BIT@_t *SA, saidx@W64BIT@_t SAsize, + saidx@W64BIT@_t *left); + +/** + * Search for the character c in the string T. + * @param T[0..Tsize-1] The input string. + * @param Tsize The length of the given string. + * @param SA[0..SAsize-1] The input suffix array. + * @param SAsize The length of the given suffix array. + * @param c The input character. + * @param idx The output index. + * @return The count of matches if no error occurred, -1 otherwise. + */ +DIVSUFSORT_API +saidx@W64BIT@_t +sa_simplesearch@W64BIT@(const sauchar_t *T, saidx@W64BIT@_t Tsize, + const saidx@W64BIT@_t *SA, saidx@W64BIT@_t SAsize, + saint_t c, saidx@W64BIT@_t *left); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* _DIVSUFSORT@W64BIT@_H */ diff --git a/tools/rasm/apultra-master/src/libdivsufsort/include/divsufsort_config.h b/tools/rasm/apultra-master/src/libdivsufsort/include/divsufsort_config.h new file mode 100644 index 0000000..4054a8a --- /dev/null +++ b/tools/rasm/apultra-master/src/libdivsufsort/include/divsufsort_config.h @@ -0,0 +1,9 @@ +#define HAVE_STRING_H 1 +#define HAVE_STDLIB_H 1 +#define HAVE_MEMORY_H 1 +#define HAVE_STDINT_H 1 +#define INLINE inline + +#ifdef _MSC_VER +#pragma warning( disable : 4244 ) +#endif /* _MSC_VER */ diff --git a/tools/rasm/apultra-master/src/libdivsufsort/include/divsufsort_private.h b/tools/rasm/apultra-master/src/libdivsufsort/include/divsufsort_private.h new file mode 100644 index 0000000..b4d97ad --- /dev/null +++ b/tools/rasm/apultra-master/src/libdivsufsort/include/divsufsort_private.h @@ -0,0 +1,205 @@ +/* + * divsufsort_private.h for libdivsufsort + * Copyright (c) 2003-2008 Yuta Mori 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 _DIVSUFSORT_PRIVATE_H +#define _DIVSUFSORT_PRIVATE_H 1 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "divsufsort_config.h" +#include +#include +#if HAVE_STRING_H +# include +#endif +#if HAVE_STDLIB_H +# include +#endif +#if HAVE_MEMORY_H +# include +#endif +#if HAVE_STDDEF_H +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_INTTYPES_H +# include +#else +# if HAVE_STDINT_H +# include +# endif +#endif +#if defined(BUILD_DIVSUFSORT64) +# include "divsufsort64.h" +# ifndef SAIDX_T +# define SAIDX_T +# define saidx_t saidx64_t +# endif /* SAIDX_T */ +# ifndef PRIdSAIDX_T +# define PRIdSAIDX_T PRIdSAIDX64_T +# endif /* PRIdSAIDX_T */ +# define divsufsort divsufsort64 +# define divbwt divbwt64 +# define divsufsort_version divsufsort64_version +# define bw_transform bw_transform64 +# define inverse_bw_transform inverse_bw_transform64 +# define sufcheck sufcheck64 +# define sa_search sa_search64 +# define sa_simplesearch sa_simplesearch64 +# define sssort sssort64 +# define trsort trsort64 +#else +# include "divsufsort.h" +#endif + + +/*- Constants -*/ +#if !defined(UINT8_MAX) +# define UINT8_MAX (255) +#endif /* UINT8_MAX */ +#if defined(ALPHABET_SIZE) && (ALPHABET_SIZE < 1) +# undef ALPHABET_SIZE +#endif +#if !defined(ALPHABET_SIZE) +# define ALPHABET_SIZE (UINT8_MAX + 1) +#endif +/* for divsufsort.c */ +#define BUCKET_A_SIZE (ALPHABET_SIZE) +#define BUCKET_B_SIZE (ALPHABET_SIZE * ALPHABET_SIZE) +/* for sssort.c */ +#if defined(SS_INSERTIONSORT_THRESHOLD) +# if SS_INSERTIONSORT_THRESHOLD < 1 +# undef SS_INSERTIONSORT_THRESHOLD +# define SS_INSERTIONSORT_THRESHOLD (1) +# endif +#else +# define SS_INSERTIONSORT_THRESHOLD (8) +#endif +#if defined(SS_BLOCKSIZE) +# if SS_BLOCKSIZE < 0 +# undef SS_BLOCKSIZE +# define SS_BLOCKSIZE (0) +# elif 32768 <= SS_BLOCKSIZE +# undef SS_BLOCKSIZE +# define SS_BLOCKSIZE (32767) +# endif +#else +# define SS_BLOCKSIZE (1024) +#endif +/* minstacksize = log(SS_BLOCKSIZE) / log(3) * 2 */ +#if SS_BLOCKSIZE == 0 +# if defined(BUILD_DIVSUFSORT64) +# define SS_MISORT_STACKSIZE (96) +# else +# define SS_MISORT_STACKSIZE (64) +# endif +#elif SS_BLOCKSIZE <= 4096 +# define SS_MISORT_STACKSIZE (16) +#else +# define SS_MISORT_STACKSIZE (24) +#endif +#if defined(BUILD_DIVSUFSORT64) +# define SS_SMERGE_STACKSIZE (64) +#else +# define SS_SMERGE_STACKSIZE (32) +#endif +/* for trsort.c */ +#define TR_INSERTIONSORT_THRESHOLD (8) +#if defined(BUILD_DIVSUFSORT64) +# define TR_STACKSIZE (96) +#else +# define TR_STACKSIZE (64) +#endif + + +/*- Macros -*/ +#ifndef SWAP +# define SWAP(_a, _b) do { t = (_a); (_a) = (_b); (_b) = t; } while(0) +#endif /* SWAP */ +#ifndef MIN +# define MIN(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) +#endif /* MIN */ +#ifndef MAX +# define MAX(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) +#endif /* MAX */ +#define STACK_PUSH(_a, _b, _c, _d)\ + do {\ + assert(ssize < STACK_SIZE);\ + stack[ssize].a = (_a), stack[ssize].b = (_b),\ + stack[ssize].c = (_c), stack[ssize++].d = (_d);\ + } while(0) +#define STACK_PUSH5(_a, _b, _c, _d, _e)\ + do {\ + assert(ssize < STACK_SIZE);\ + stack[ssize].a = (_a), stack[ssize].b = (_b),\ + stack[ssize].c = (_c), stack[ssize].d = (_d), stack[ssize++].e = (_e);\ + } while(0) +#define STACK_POP(_a, _b, _c, _d)\ + do {\ + assert(0 <= ssize);\ + if(ssize == 0) { return; }\ + (_a) = stack[--ssize].a, (_b) = stack[ssize].b,\ + (_c) = stack[ssize].c, (_d) = stack[ssize].d;\ + } while(0) +#define STACK_POP5(_a, _b, _c, _d, _e)\ + do {\ + assert(0 <= ssize);\ + if(ssize == 0) { return; }\ + (_a) = stack[--ssize].a, (_b) = stack[ssize].b,\ + (_c) = stack[ssize].c, (_d) = stack[ssize].d, (_e) = stack[ssize].e;\ + } while(0) +/* for divsufsort.c */ +#define BUCKET_A(_c0) bucket_A[(_c0)] +#if ALPHABET_SIZE == 256 +#define BUCKET_B(_c0, _c1) (bucket_B[((_c1) << 8) | (_c0)]) +#define BUCKET_BSTAR(_c0, _c1) (bucket_B[((_c0) << 8) | (_c1)]) +#else +#define BUCKET_B(_c0, _c1) (bucket_B[(_c1) * ALPHABET_SIZE + (_c0)]) +#define BUCKET_BSTAR(_c0, _c1) (bucket_B[(_c0) * ALPHABET_SIZE + (_c1)]) +#endif + + +/*- Private Prototypes -*/ +/* sssort.c */ +void +sssort(const sauchar_t *Td, const saidx_t *PA, + saidx_t *first, saidx_t *last, + saidx_t *buf, saidx_t bufsize, + saidx_t depth, saidx_t n, saint_t lastsuffix); +/* trsort.c */ +void +trsort(saidx_t *ISA, saidx_t *SA, saidx_t n, saidx_t depth); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* _DIVSUFSORT_PRIVATE_H */ diff --git a/tools/rasm/apultra-master/src/libdivsufsort/include/lfs.h.cmake b/tools/rasm/apultra-master/src/libdivsufsort/include/lfs.h.cmake new file mode 100644 index 0000000..d5b84a8 --- /dev/null +++ b/tools/rasm/apultra-master/src/libdivsufsort/include/lfs.h.cmake @@ -0,0 +1,56 @@ +/* + * lfs.h for libdivsufsort + * Copyright (c) 2003-2008 Yuta Mori 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 _LFS_H +#define _LFS_H 1 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef __STRICT_ANSI__ +# define LFS_OFF_T @LFS_OFF_T@ +# define LFS_FOPEN @LFS_FOPEN@ +# define LFS_FTELL @LFS_FTELL@ +# define LFS_FSEEK @LFS_FSEEK@ +# define LFS_PRId @LFS_PRID@ +#else +# define LFS_OFF_T long +# define LFS_FOPEN fopen +# define LFS_FTELL ftell +# define LFS_FSEEK fseek +# define LFS_PRId "ld" +#endif +#ifndef PRIdOFF_T +# define PRIdOFF_T LFS_PRId +#endif + + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* _LFS_H */ diff --git a/tools/rasm/apultra-master/src/libdivsufsort/pkgconfig/CMakeLists.txt b/tools/rasm/apultra-master/src/libdivsufsort/pkgconfig/CMakeLists.txt new file mode 100644 index 0000000..ee7063c --- /dev/null +++ b/tools/rasm/apultra-master/src/libdivsufsort/pkgconfig/CMakeLists.txt @@ -0,0 +1,9 @@ +## generate libdivsufsort.pc ## +set(W64BIT "") +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/libdivsufsort.pc.cmake" "${CMAKE_CURRENT_BINARY_DIR}/libdivsufsort.pc" @ONLY) +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libdivsufsort.pc" DESTINATION ${CMAKE_INSTALL_PKGCONFIGDIR}) +if(BUILD_DIVSUFSORT64) + set(W64BIT "64") + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/libdivsufsort.pc.cmake" "${CMAKE_CURRENT_BINARY_DIR}/libdivsufsort64.pc" @ONLY) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libdivsufsort64.pc" DESTINATION ${CMAKE_INSTALL_PKGCONFIGDIR}) +endif(BUILD_DIVSUFSORT64) diff --git a/tools/rasm/apultra-master/src/libdivsufsort/pkgconfig/libdivsufsort.pc.cmake b/tools/rasm/apultra-master/src/libdivsufsort/pkgconfig/libdivsufsort.pc.cmake new file mode 100644 index 0000000..6419d1e --- /dev/null +++ b/tools/rasm/apultra-master/src/libdivsufsort/pkgconfig/libdivsufsort.pc.cmake @@ -0,0 +1,11 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=@CMAKE_INSTALL_LIBDIR@ +includedir=@CMAKE_INSTALL_INCLUDEDIR@ + +Name: @PROJECT_NAME@@W64BIT@ +Description: @PROJECT_DESCRIPTION@ +Version: @PROJECT_VERSION_FULL@ +URL: @PROJECT_URL@ +Libs: -L${libdir} -ldivsufsort@W64BIT@ +Cflags: -I${includedir} diff --git a/tools/rasm/apultra-master/src/matchfinder.c b/tools/rasm/apultra-master/src/matchfinder.c new file mode 100644 index 0000000..a9987f9 --- /dev/null +++ b/tools/rasm/apultra-master/src/matchfinder.c @@ -0,0 +1,449 @@ +/* + * matchfinder.c - LZ match finder implementation + * + * The following copying information applies to this specific source code file: + * + * Written in 2019 by Emmanuel Marty + * Portions written in 2014-2015 by Eric Biggers + * + * To the extent possible under law, the author(s) have dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide via the Creative Commons Zero 1.0 Universal Public Domain + * Dedication (the "CC0"). + * + * This software 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 CC0 for more details. + * + * You should have received a copy of the CC0 along with this software; if not + * see . + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by cap by Sven-Åke Dahl. https://github.com/svendahl/cap + * Also inspired by Charles Bloom's compression blog. http://cbloomrants.blogspot.com/ + * With ideas from LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help and support from spke + * + */ + +#include +#include +#include "matchfinder.h" +#include "format.h" +#include "libapultra.h" + +/** + * Hash index into TAG_BITS + * + * @param nIndex index value + * + * @return hash + */ +static inline int apultra_get_index_tag(unsigned int nIndex) { + return (int)(((unsigned long long)nIndex * 11400714819323198485ULL) >> (64ULL - TAG_BITS)); +} + +/** + * Parse input data, build suffix array and overlaid data structures to speed up match finding + * + * @param pCompressor compression context + * @param pInWindow pointer to input data window (previously compressed bytes + bytes to compress) + * @param nInWindowSize total input size in bytes (previously compressed bytes + bytes to compress) + * + * @return 0 for success, non-zero for failure + */ +int apultra_build_suffix_array(apultra_compressor *pCompressor, const unsigned char *pInWindow, const int nInWindowSize) { + unsigned long long *intervals = pCompressor->intervals; + + /* Build suffix array from input data */ + saidx_t *suffixArray = (saidx_t*)intervals; + if (divsufsort_build_array(&pCompressor->divsufsort_context, pInWindow, suffixArray, nInWindowSize) != 0) { + return 100; + } + + int i, r; + + for (i = nInWindowSize - 1; i >= 0; i--) { + intervals[i] = suffixArray[i]; + } + + int *PLCP = (int*)pCompressor->pos_data; /* Use temporarily */ + int *Phi = PLCP; + int nCurLen = 0; + + /* Compute the permuted LCP first (Kärkkäinen method) */ + Phi[intervals[0]] = -1; + for (i = 1; i < nInWindowSize; i++) + Phi[intervals[i]] = (unsigned int)intervals[i - 1]; + for (i = 0; i < nInWindowSize; i++) { + if (Phi[i] == -1) { + PLCP[i] = 0; + continue; + } + int nMaxLen = (i > Phi[i]) ? (nInWindowSize - i) : (nInWindowSize - Phi[i]); + while (nCurLen < nMaxLen && pInWindow[i + nCurLen] == pInWindow[Phi[i] + nCurLen]) nCurLen++; + PLCP[i] = nCurLen; + if (nCurLen > 0) + nCurLen--; + } + + /* Rotate permuted LCP into the LCP. This has better cache locality than the direct Kasai LCP method. This also + * saves us from having to build the inverse suffix array index, as the LCP is calculated without it using this method, + * and the interval builder below doesn't need it either. */ + intervals[0] &= POS_MASK; + + for (i = 1; i < nInWindowSize; i++) { + int nIndex = (int)(intervals[i] & POS_MASK); + int nLen = PLCP[nIndex]; + if (nLen < MIN_MATCH_SIZE) + nLen = 0; + if (nLen > LCP_MAX) + nLen = LCP_MAX; + int nTaggedLen = 0; + if (nLen) + nTaggedLen = (nLen << TAG_BITS) | (apultra_get_index_tag((unsigned int)nIndex) & ((1 << TAG_BITS) - 1)); + intervals[i] = ((unsigned long long)nIndex) | (((unsigned long long)nTaggedLen) << LCP_SHIFT); + } + + /** + * Build intervals for finding matches + * + * Methodology and code fragment taken from wimlib (CC0 license): + * https://wimlib.net/git/?p=wimlib;a=blob_plain;f=src/lcpit_matchfinder.c;h=a2d6a1e0cd95200d1f3a5464d8359d5736b14cbe;hb=HEAD + */ + unsigned long long * const SA_and_LCP = intervals; + unsigned long long *pos_data = pCompressor->pos_data; + unsigned long long next_interval_idx; + unsigned long long *top = pCompressor->open_intervals; + unsigned long long prev_pos = SA_and_LCP[0] & POS_MASK; + + *top = 0; + intervals[0] = 0; + next_interval_idx = 1; + + for (r = 1; r < nInWindowSize; r++) { + const unsigned long long next_pos = SA_and_LCP[r] & POS_MASK; + const unsigned long long next_lcp = SA_and_LCP[r] & LCP_MASK; + const unsigned long long top_lcp = *top & LCP_MASK; + + if (next_lcp == top_lcp) { + /* Continuing the deepest open interval */ + pos_data[prev_pos] = *top; + } + else if (next_lcp > top_lcp) { + /* Opening a new interval */ + *++top = next_lcp | next_interval_idx++; + pos_data[prev_pos] = *top; + } + else { + /* Closing the deepest open interval */ + pos_data[prev_pos] = *top; + for (;;) { + const unsigned long long closed_interval_idx = *top-- & POS_MASK; + const unsigned long long superinterval_lcp = *top & LCP_MASK; + + if (next_lcp == superinterval_lcp) { + /* Continuing the superinterval */ + intervals[closed_interval_idx] = *top; + break; + } + else if (next_lcp > superinterval_lcp) { + /* Creating a new interval that is a + * superinterval of the one being + * closed, but still a subinterval of + * its superinterval */ + *++top = next_lcp | next_interval_idx++; + intervals[closed_interval_idx] = *top; + break; + } + else { + /* Also closing the superinterval */ + intervals[closed_interval_idx] = *top; + } + } + } + prev_pos = next_pos; + } + + /* Close any still-open intervals. */ + pos_data[prev_pos] = *top; + for (; top > pCompressor->open_intervals; top--) + intervals[*top & POS_MASK] = *(top - 1); + + /* Success */ + return 0; +} + +/** + * Find matches at the specified offset in the input window + * + * @param pCompressor compression context + * @param nOffset offset to find matches at, in the input window + * @param pMatches pointer to returned matches + * @param pMatchDepth pointer to returned match depths + * @param pMatch1 pointer to 1-byte length, 4 bit offset match + * @param nMaxMatches maximum number of matches to return (0 for none) + * @param nBlockFlags bit 0: 1 for first block, 0 otherwise; bit 1: 1 for last block, 0 otherwise + * + * @return number of matches + */ +int apultra_find_matches_at(apultra_compressor *pCompressor, const int nOffset, apultra_match *pMatches, unsigned short *pMatchDepth, unsigned char *pMatch1, const int nMaxMatches, const int nBlockFlags) { + unsigned long long *intervals = pCompressor->intervals; + unsigned long long *pos_data = pCompressor->pos_data; + unsigned long long ref; + unsigned long long super_ref; + unsigned long long match_pos; + apultra_match *matchptr; + unsigned short *depthptr; + const int nMaxOffset = pCompressor->max_offset; + + *pMatch1 = 0; + + /** + * Find matches using intervals + * + * Taken from wimlib (CC0 license): + * https://wimlib.net/git/?p=wimlib;a=blob_plain;f=src/lcpit_matchfinder.c;h=a2d6a1e0cd95200d1f3a5464d8359d5736b14cbe;hb=HEAD + */ + + /* Get the deepest lcp-interval containing the current suffix. */ + ref = pos_data[nOffset]; + + pos_data[nOffset] = 0; + + /* Ascend until we reach a visited interval, the root, or a child of the + * root. Link unvisited intervals to the current suffix as we go. */ + while ((super_ref = intervals[ref & POS_MASK]) & LCP_MASK) { + intervals[ref & POS_MASK] = nOffset | VISITED_FLAG; + ref = super_ref; + } + + if (super_ref == 0) { + /* In this case, the current interval may be any of: + * (1) the root; + * (2) an unvisited child of the root */ + + if (ref != 0) /* Not the root? */ + intervals[ref & POS_MASK] = nOffset | VISITED_FLAG; + return 0; + } + + /* Ascend indirectly via pos_data[] links. */ + match_pos = super_ref & EXCL_VISITED_MASK; + matchptr = pMatches; + depthptr = pMatchDepth; + int nPrevOffset = 0; + int nPrevLen = 0; + int nCurDepth = 0; + unsigned short *cur_depth = NULL; + + if (nOffset >= match_pos && (nBlockFlags & 3) == 3) { + int nMatchOffset = (int)(nOffset - match_pos); + int nMatchLen = (int)(ref >> (LCP_SHIFT + TAG_BITS)); + + if ((matchptr - pMatches) < nMaxMatches) { + if (nMatchOffset <= nMaxOffset) { + if (nPrevOffset && nPrevLen > 2 && nMatchOffset == (nPrevOffset - 1) && nMatchLen == (nPrevLen - 1) && cur_depth && nCurDepth < LCP_MAX) { + nCurDepth++; + *cur_depth = nCurDepth; + } + else { + nCurDepth = 0; + + cur_depth = depthptr; + matchptr->length = nMatchLen; + matchptr->offset = nMatchOffset; + *depthptr = 0; + matchptr++; + depthptr++; + } + + nPrevLen = nMatchLen; + nPrevOffset = nMatchOffset; + } + } + } + + for (;;) { + if ((super_ref = pos_data[match_pos]) > ref) { + match_pos = intervals[super_ref & POS_MASK] & EXCL_VISITED_MASK; + + if (nOffset >= match_pos && (nBlockFlags & 3) == 3) { + int nMatchOffset = (int)(nOffset - match_pos); + int nMatchLen = (int)(ref >> (LCP_SHIFT + TAG_BITS)); + + if ((matchptr - pMatches) < nMaxMatches) { + if (nMatchOffset <= nMaxOffset && abs(nMatchOffset - nPrevOffset) >= 128) { + if (nPrevOffset && nPrevLen > 2 && nMatchOffset == (nPrevOffset - 1) && nMatchLen == (nPrevLen - 1) && cur_depth && nCurDepth < LCP_MAX) { + nCurDepth++; + *cur_depth = nCurDepth | 0x8000; + } + else { + nCurDepth = 0; + + cur_depth = depthptr; + matchptr->length = nMatchLen; + matchptr->offset = nMatchOffset; + *depthptr = 0x8000; + matchptr++; + depthptr++; + } + + nPrevLen = nMatchLen; + nPrevOffset = nMatchOffset; + } + } + } + } + + while ((super_ref = pos_data[match_pos]) > ref) { + match_pos = intervals[super_ref & POS_MASK] & EXCL_VISITED_MASK; + + if (nOffset > match_pos && (nBlockFlags & 3) == 3) { + int nMatchOffset = (int)(nOffset - match_pos); + int nMatchLen = (int)(ref >> (LCP_SHIFT + TAG_BITS)); + + if ((matchptr - pMatches) < nMaxMatches) { + if (nMatchOffset <= nMaxOffset && (nMatchLen >= 3 || (nMatchLen >= 2 && (matchptr - pMatches) < (nMaxMatches - 1))) && nMatchLen < 1280 && abs(nMatchOffset - nPrevOffset) >= 128) { + if (nPrevOffset && nPrevLen > 2 && nMatchOffset == (nPrevOffset - 1) && nMatchLen == (nPrevLen - 1) && cur_depth && nCurDepth < LCP_MAX) { + nCurDepth++; + *cur_depth = nCurDepth | 0x8000; + } + else { + nCurDepth = 0; + + cur_depth = depthptr; + matchptr->length = nMatchLen; + matchptr->offset = nMatchOffset; + *depthptr = 0x8000; + matchptr++; + depthptr++; + } + + nPrevLen = nMatchLen; + nPrevOffset = nMatchOffset; + } + } + } + } + + intervals[ref & POS_MASK] = nOffset | VISITED_FLAG; + pos_data[match_pos] = (unsigned long long)ref; + + int nMatchOffset = (int)(nOffset - match_pos); + int nMatchLen = (int)(ref >> (LCP_SHIFT + TAG_BITS)); + + if ((matchptr - pMatches) < nMaxMatches) { + if (nMatchOffset <= nMaxOffset && nMatchOffset != nPrevOffset) { + if (nPrevOffset && nPrevLen > 2 && nMatchOffset == (nPrevOffset - 1) && nMatchLen == (nPrevLen - 1) && cur_depth && nCurDepth < LCP_MAX) { + nCurDepth++; + *cur_depth = nCurDepth; + } + else { + nCurDepth = 0; + + cur_depth = depthptr; + matchptr->length = nMatchLen; + matchptr->offset = nMatchOffset; + *depthptr = 0; + matchptr++; + depthptr++; + } + + nPrevLen = nMatchLen; + nPrevOffset = nMatchOffset; + } + } + + if (nMatchOffset && nMatchOffset < 16 && nMatchLen) + *pMatch1 = nMatchOffset; + + if (super_ref == 0) + break; + ref = super_ref; + match_pos = intervals[ref & POS_MASK] & EXCL_VISITED_MASK; + + if (nOffset > match_pos && (nBlockFlags & 3) == 3) { + int nMatchOffset = (int)(nOffset - match_pos); + int nMatchLen = (int)(ref >> (LCP_SHIFT + TAG_BITS)); + + if ((matchptr - pMatches) < nMaxMatches) { + if (nMatchOffset <= nMaxOffset && nMatchLen >= 2 && abs(nMatchOffset - nPrevOffset) >= 128) { + if (nPrevOffset && nPrevLen > 2 && nMatchOffset == (nPrevOffset - 1) && nMatchLen == (nPrevLen - 1) && cur_depth && nCurDepth < LCP_MAX) { + nCurDepth++; + *cur_depth = nCurDepth | 0x8000; + } + else { + nCurDepth = 0; + + cur_depth = depthptr; + matchptr->length = nMatchLen; + matchptr->offset = nMatchOffset; + *depthptr = 0x8000; + matchptr++; + depthptr++; + } + + nPrevLen = nMatchLen; + nPrevOffset = nMatchOffset; + } + } + } + } + + return (int)(matchptr - pMatches); +} + +/** + * Skip previously compressed bytes + * + * @param pCompressor compression context + * @param nStartOffset current offset in input window (typically 0) + * @param nEndOffset offset to skip to in input window (typically the number of previously compressed bytes) + */ +void apultra_skip_matches(apultra_compressor *pCompressor, const int nStartOffset, const int nEndOffset) { + apultra_match match; + unsigned short depth; + unsigned char match1; + int i; + + /* Skipping still requires scanning for matches, as this also performs a lazy update of the intervals. However, + * we don't store the matches. */ + for (i = nStartOffset; i < nEndOffset; i++) { + apultra_find_matches_at(pCompressor, i, &match, &depth, &match1, 0, 0); + } +} + +/** + * Find all matches for the data to be compressed + * + * @param pCompressor compression context + * @param nMatchesPerOffset maximum number of matches to store for each offset + * @param nStartOffset current offset in input window (typically the number of previously compressed bytes) + * @param nEndOffset offset to end finding matches at (typically the size of the total input window in bytes + * @param nBlockFlags bit 0: 1 for first block, 0 otherwise; bit 1: 1 for last block, 0 otherwise + */ +void apultra_find_all_matches(apultra_compressor *pCompressor, const int nMatchesPerOffset, const int nStartOffset, const int nEndOffset, const int nBlockFlags) { + apultra_match *pMatch = pCompressor->match; + unsigned short *pMatchDepth = pCompressor->match_depth; + unsigned char *pMatch1 = pCompressor->match1; + int i; + + for (i = nStartOffset; i < nEndOffset; i++) { + int nMatches = apultra_find_matches_at(pCompressor, i, pMatch, pMatchDepth, pMatch1, nMatchesPerOffset, nBlockFlags); + + while (nMatches < nMatchesPerOffset) { + pMatch[nMatches].length = 0; + pMatch[nMatches].offset = 0; + pMatchDepth[nMatches] = 0; + nMatches++; + } + + pMatch += nMatchesPerOffset; + pMatchDepth += nMatchesPerOffset; + pMatch1++; + } +} diff --git a/tools/rasm/apultra-master/src/matchfinder.h b/tools/rasm/apultra-master/src/matchfinder.h new file mode 100644 index 0000000..7d68eaf --- /dev/null +++ b/tools/rasm/apultra-master/src/matchfinder.h @@ -0,0 +1,94 @@ +/* + * matchfinder.h - LZ match finder definitions + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by cap by Sven-Åke Dahl. https://github.com/svendahl/cap + * Also inspired by Charles Bloom's compression blog. http://cbloomrants.blogspot.com/ + * With ideas from LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help and support from spke + * + */ + +#ifndef _MATCHFINDER_H +#define _MATCHFINDER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declarations */ +typedef struct _apultra_match apultra_match; +typedef struct _apultra_compressor apultra_compressor; + +/** + * Parse input data, build suffix array and overlaid data structures to speed up match finding + * + * @param pCompressor compression context + * @param pInWindow pointer to input data window (previously compressed bytes + bytes to compress) + * @param nInWindowSize total input size in bytes (previously compressed bytes + bytes to compress) + * + * @return 0 for success, non-zero for failure + */ +int apultra_build_suffix_array(apultra_compressor *pCompressor, const unsigned char *pInWindow, const int nInWindowSize); + +/** + * Find matches at the specified offset in the input window + * + * @param pCompressor compression context + * @param nOffset offset to find matches at, in the input window + * @param pMatches pointer to returned matches + * @param pMatchDepth pointer to returned match depths + * @param pMatch1 pointer to 1-byte length, 4 bit offset match + * @param nMaxMatches maximum number of matches to return (0 for none) + * @param nBlockFlags bit 0: 1 for first block, 0 otherwise; bit 1: 1 for last block, 0 otherwise + * + * @return number of matches + */ +int apultra_find_matches_at(apultra_compressor *pCompressor, const int nOffset, apultra_match *pMatches, unsigned short *pMatchDepth, unsigned char *pMatch1, const int nMaxMatches, const int nBlockFlags); + +/** + * Skip previously compressed bytes + * + * @param pCompressor compression context + * @param nStartOffset current offset in input window (typically 0) + * @param nEndOffset offset to skip to in input window (typically the number of previously compressed bytes) + */ +void apultra_skip_matches(apultra_compressor *pCompressor, const int nStartOffset, const int nEndOffset); + +/** + * Find all matches for the data to be compressed + * + * @param pCompressor compression context + * @param nMatchesPerOffset maximum number of matches to store for each offset + * @param nStartOffset current offset in input window (typically the number of previously compressed bytes) + * @param nEndOffset offset to end finding matches at (typically the size of the total input window in bytes + * @param nBlockFlags bit 0: 1 for first block, 0 otherwise; bit 1: 1 for last block, 0 otherwise + */ +void apultra_find_all_matches(apultra_compressor *pCompressor, const int nMatchesPerOffset, const int nStartOffset, const int nEndOffset, const int nBlockFlags); + +#ifdef __cplusplus +} +#endif + +#endif /* _MATCHFINDER_H */ diff --git a/tools/rasm/apultra-master/src/shrink.c b/tools/rasm/apultra-master/src/shrink.c new file mode 100644 index 0000000..4b2a4db --- /dev/null +++ b/tools/rasm/apultra-master/src/shrink.c @@ -0,0 +1,1597 @@ +/* + * shrink.c - compressor implementation + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by cap by Sven-Åke Dahl. https://github.com/svendahl/cap + * Also inspired by Charles Bloom's compression blog. http://cbloomrants.blogspot.com/ + * With ideas from LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help and support from spke + * + */ + +#include +#include +#include +#include "libapultra.h" +#include "matchfinder.h" +#include "shrink.h" +#include "format.h" + +#define TOKEN_CODE_LARGE_MATCH 2 /* 10 */ +#define TOKEN_SIZE_LARGE_MATCH 2 + +#define TOKEN_CODE_7BIT_MATCH 6 /* 110 */ +#define TOKEN_SIZE_7BIT_MATCH 3 + +#define TOKEN_CODE_4BIT_MATCH 7 /* 111 */ +#define TOKEN_SIZE_4BIT_MATCH 3 + +#define CountShift(N,bits) if ((N)>>(bits)) { (N)>>=(bits); (n) += (bits); } + +/** Gamma2 bit counts for common values, up to 255 */ +static char _gamma2_size[256] = { + 0, 0, 2, 2, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +}; + +/** + * Write bitpacked value to output (compressed) buffer + * + * @param pOutData pointer to output buffer + * @param nOutOffset current write index into output buffer + * @param nMaxOutDataSize maximum size of output buffer, in bytes + * @param nValue value to write + * @param nBits number of least significant bits to write in value + * @param nCurBitsOffset write index into output buffer, of current byte being filled with bits + * @param nCurBitShift bit shift count + * + * @return updated write index into output buffer, or -1 in case of an error + */ +static int apultra_write_bits(unsigned char *pOutData, int nOutOffset, const int nMaxOutDataSize, const int nValue, const int nBits, int *nCurBitsOffset, int *nCurBitShift) { + int i; + + if (nOutOffset < 0) return -1; + + for (i = nBits - 1; i >= 0; i--) { + if ((*nCurBitsOffset) == INT_MIN) { + /* Allocate a new byte in the stream to pack bits in */ + if (nOutOffset >= nMaxOutDataSize) return -1; + (*nCurBitsOffset) = nOutOffset; + (*nCurBitShift) = 7; + pOutData[nOutOffset++] = 0; + } + + pOutData[(*nCurBitsOffset)] |= ((nValue >> i) & 1) << (*nCurBitShift); + + (*nCurBitShift) --; + if ((*nCurBitShift) == -1) { + /* Current byte is full */ + (*nCurBitsOffset) = INT_MIN; + } + } + + return nOutOffset; +} + +/** + * Get size of gamma2 encoded value + * + * @param nValue value of evaluate (2..n) + * + * @return number of bits required + */ +static int apultra_get_gamma2_size(int nValue) { + if (nValue >= 0 && nValue < 256) + return _gamma2_size[nValue]; + else { + unsigned int n = 0; + CountShift(nValue, 16); + CountShift(nValue, 8); + CountShift(nValue, 4); + CountShift(nValue, 2); + CountShift(nValue, 1); + + return n << 1; + } +} + +/** + * Write gamma2 encoded value to output (compressed) buffer + * + * @param pOutData pointer to output buffer + * @param nOutOffset current write index into output buffer + * @param nMaxOutDataSize maximum size of output buffer, in bytes + * @param nValue value of write (2..n) + * @param nCurBitsOffset write index into output buffer, of current byte being filled with bits + * @param nCurBitShift bit shift count + * + * @return updated write index into output buffer, or -1 in case of an error + */ +static int apultra_write_gamma2_value(unsigned char *pOutData, int nOutOffset, const int nMaxOutDataSize, int nValue, int *nCurBitsOffset, int *nCurBitShift) { + int msb = 30; + while ((nValue >> msb--) == 0); + + while (msb > 0) { + int bit = (nValue >> msb) & 1; + + nOutOffset = apultra_write_bits(pOutData, nOutOffset, nMaxOutDataSize, bit, 1, nCurBitsOffset, nCurBitShift); + msb--; + nOutOffset = apultra_write_bits(pOutData, nOutOffset, nMaxOutDataSize, 1, 1, nCurBitsOffset, nCurBitShift); + } + + nOutOffset = apultra_write_bits(pOutData, nOutOffset, nMaxOutDataSize, nValue & 1, 1, nCurBitsOffset, nCurBitShift); + nOutOffset = apultra_write_bits(pOutData, nOutOffset, nMaxOutDataSize, 0, 1, nCurBitsOffset, nCurBitShift); + return nOutOffset; +} + +/** + * Get the number of extra bits required to represent a match offset + * + * @param nLength match length + * @param nMatchOffset match offset + * @param nFollowsLiteral non-zero if the match follows a literal, zero if it immediately follows another match + * + * @return number of extra bits required + */ +static inline int apultra_get_offset_varlen_size(const int nLength, const int nMatchOffset, const int nFollowsLiteral) { + if (nLength <= 3 && nMatchOffset < 128) + return 8 + TOKEN_SIZE_7BIT_MATCH; + else { + if (nFollowsLiteral) + return 8 + TOKEN_SIZE_LARGE_MATCH + apultra_get_gamma2_size((nMatchOffset >> 8) + 3); + else + return 8 + TOKEN_SIZE_LARGE_MATCH + apultra_get_gamma2_size((nMatchOffset >> 8) + 2); + } +} + +/** + * Get the number of extra bits required to represent a match length + * + * @param nLength match length + * @param nMatchOffset match offset + * + * @return number of extra bits required + */ +static inline int apultra_get_match_varlen_size(int nLength, const int nMatchOffset) { + if (nLength <= 3 && nMatchOffset < 128) + return 0; + else { + if (nMatchOffset < 128 || nMatchOffset >= MINMATCH4_OFFSET) + return apultra_get_gamma2_size(nLength - 2); + else if (nMatchOffset < MINMATCH3_OFFSET) + return apultra_get_gamma2_size(nLength); + else + return apultra_get_gamma2_size(nLength - 1); + } +} + +/** + * Insert forward rep candidate + * + * @param pCompressor compression context + * @param pInWindow pointer to input data window (previously compressed bytes + bytes to compress) + * @param i input data window position whose matches are being considered + * @param nMatchOffset match offset to use as rep candidate + * @param nStartOffset current offset in input window (typically the number of previously compressed bytes) + * @param nEndOffset offset to end finding matches at (typically the size of the total input window in bytes + * @param nArrivalsPerPosition maximum number of arrivals per input buffer position + * @param nDepth current insertion depth + */ +static void apultra_insert_forward_match(apultra_compressor *pCompressor, const unsigned char *pInWindow, const int i, const int nMatchOffset, const int nStartOffset, const int nEndOffset, const int nArrivalsPerPosition, int nDepth) { + apultra_arrival *arrival = pCompressor->arrival + ((i - nStartOffset) * nArrivalsPerPosition); + const int *rle_end = (int*)pCompressor->intervals /* reuse */; + int* visited = ((int*)pCompressor->pos_data) - nStartOffset /* reuse */; + int j; + + for (j = 0; j < nArrivalsPerPosition && arrival[j].from_slot; j++) { + int nRepOffset = arrival[j].rep_offset; + + if (arrival[j].follows_literal && nMatchOffset != nRepOffset && nRepOffset) { + int nRepPos = arrival[j].rep_pos; + + if (nRepPos && + nRepPos >= nMatchOffset && + nRepPos < nEndOffset && + pCompressor->match[((nRepPos - nStartOffset) << MATCHES_PER_INDEX_SHIFT) + NMATCHES_PER_INDEX - 1].length == 0) { + + if (visited[nRepPos] != nMatchOffset) { + visited[nRepPos] = nMatchOffset; + + const unsigned char* pInWindowAtRepOffset = pInWindow + nRepPos; + + if (pInWindowAtRepOffset[0] == pInWindowAtRepOffset[-nMatchOffset]) { + int nMaxRepLen = nEndOffset - nRepPos; + if (nMaxRepLen > LCP_MAX) + nMaxRepLen = LCP_MAX; + const unsigned char* pInWindowMax = pInWindowAtRepOffset + nMaxRepLen; + + int nLen0 = rle_end[nRepPos - nMatchOffset] - (nRepPos - nMatchOffset); + int nLen1 = rle_end[nRepPos] - (nRepPos); + int nMinLen = (nLen0 < nLen1) ? nLen0 : nLen1; + + if (nMinLen > nMaxRepLen) + nMinLen = nMaxRepLen; + pInWindowAtRepOffset += nMinLen; + + while ((pInWindowAtRepOffset + 8) < pInWindowMax && !memcmp(pInWindowAtRepOffset, pInWindowAtRepOffset - nMatchOffset, 8)) + pInWindowAtRepOffset += 8; + while ((pInWindowAtRepOffset + 4) < pInWindowMax && !memcmp(pInWindowAtRepOffset, pInWindowAtRepOffset - nMatchOffset, 4)) + pInWindowAtRepOffset += 4; + while (pInWindowAtRepOffset < pInWindowMax && pInWindowAtRepOffset[0] == pInWindowAtRepOffset[-nMatchOffset]) + pInWindowAtRepOffset++; + + int nCurRepLen = (int)(pInWindowAtRepOffset - (pInWindow + nRepPos)); + + if (nCurRepLen >= 2) { + apultra_match* fwd_match = pCompressor->match + ((nRepPos - nStartOffset) << MATCHES_PER_INDEX_SHIFT); + unsigned short* fwd_depth = pCompressor->match_depth + ((nRepPos - nStartOffset) << MATCHES_PER_INDEX_SHIFT); + int r; + + for (r = 0; r < NMATCHES_PER_INDEX && fwd_match[r].length >= MIN_MATCH_SIZE; r++) { + if (fwd_match[r].offset == nMatchOffset && (fwd_depth[r] & 0x7fff) == 0) { + if ((int)fwd_match[r].length < nCurRepLen) { + fwd_match[r].length = nCurRepLen; + fwd_depth[r] = 0; + } + r = NMATCHES_PER_INDEX; + break; + } + } + + if (r < NMATCHES_PER_INDEX) { + fwd_match[r].offset = nMatchOffset; + fwd_match[r].length = nCurRepLen; + fwd_depth[r] = 0; + + if (nDepth < 9) + apultra_insert_forward_match(pCompressor, pInWindow, nRepPos, nMatchOffset, nStartOffset, nEndOffset, nArrivalsPerPosition, nDepth + 1); + } + } + } + } + } + } + } +} + +/** + * Attempt to pick optimal matches, so as to produce the smallest possible output that decompresses to the same input + * + * @param pCompressor compression context + * @param pInWindow pointer to input data window (previously compressed bytes + bytes to compress) + * @param nStartOffset current offset in input window (typically the number of previously compressed bytes) + * @param nEndOffset offset to end finding matches at (typically the size of the total input window in bytes + * @param nInsertForwardReps non-zero to insert forward repmatch candidates, zero to use the previously inserted candidates + * @param nCurRepMatchOffset starting rep offset for this block + * @param nBlockFlags bit 0: 1 for first block, 0 otherwise; bit 1: 1 for last block, 0 otherwise + * @param nArrivalsPerPosition maximum number of arrivals per input buffer position + */ +static void apultra_optimize_forward(apultra_compressor *pCompressor, const unsigned char *pInWindow, const int nStartOffset, const int nEndOffset, const int nInsertForwardReps, const int *nCurRepMatchOffset, const int nBlockFlags, const int nArrivalsPerPosition) { + apultra_arrival *arrival = pCompressor->arrival - (nStartOffset * nArrivalsPerPosition); + const int* rle_end = (int*)pCompressor->intervals /* reuse */; + int* visited = ((int*)pCompressor->pos_data) - nStartOffset /* reuse */; + int i, j, n; + + if ((nEndOffset - nStartOffset) > pCompressor->block_size) return; + + memset(arrival + (nStartOffset * nArrivalsPerPosition), 0, sizeof(apultra_arrival) * ((nEndOffset - nStartOffset + 1) * nArrivalsPerPosition)); + + arrival[nStartOffset * nArrivalsPerPosition].from_slot = -1; + arrival[nStartOffset * nArrivalsPerPosition].rep_offset = *nCurRepMatchOffset; + + for (i = (nStartOffset * nArrivalsPerPosition); i != ((nEndOffset+1) * nArrivalsPerPosition); i++) { + arrival[i].cost = 0x40000000; + } + + if (nInsertForwardReps) { + memset(visited + nStartOffset, 0, (nEndOffset - nStartOffset) * sizeof(int)); + } + + for (i = nStartOffset; i != nEndOffset; i++) { + apultra_arrival *cur_arrival = &arrival[i * nArrivalsPerPosition]; + int m; + + unsigned char *match1 = pCompressor->match1 + (i - nStartOffset); + int nShortOffset; + int nShortLen; + int nLiteralCost; + + if ((pInWindow[i] != 0 && (*match1) == 0) || (i == nStartOffset && (nBlockFlags & 1))) { + nShortOffset = 0; + nShortLen = 0; + nLiteralCost = 9 /* literal bit + literal byte */; + } + else { + nShortOffset = (pInWindow[i] == 0) ? 0 : (*match1); + nShortLen = 1; + nLiteralCost = 4 + TOKEN_SIZE_4BIT_MATCH /* command and offset cost; no length cost */; + } + + for (j = 0; j < nArrivalsPerPosition && cur_arrival[j].from_slot; j++) { + int nPrevCost = cur_arrival[j].cost & 0x3fffffff; + int nCodingChoiceCost = nPrevCost + nLiteralCost; + + apultra_arrival *pDestSlots = &cur_arrival[nArrivalsPerPosition]; + if (nCodingChoiceCost <= pDestSlots[nArrivalsPerPosition - 1].cost) { + int exists = 0; + + for (n = 0; + n < nArrivalsPerPosition && pDestSlots[n].cost < nCodingChoiceCost; + n++) { + if (pDestSlots[n].rep_offset == cur_arrival[j].rep_offset) { + exists = 1; + break; + } + } + + if (!exists) { + int nScore = cur_arrival[j].score + (nShortOffset ? 3 : 1); + + for (; + n < nArrivalsPerPosition && pDestSlots[n].cost == nCodingChoiceCost && nScore >= pDestSlots[n].score; + n++) { + if (pDestSlots[n].rep_offset == cur_arrival[j].rep_offset) { + exists = 1; + break; + } + } + + if (!exists) { + if (n < nArrivalsPerPosition) { + int nn; + + for (nn = n; + nn < nArrivalsPerPosition && pDestSlots[nn].cost == nCodingChoiceCost; + nn++) { + if (pDestSlots[nn].rep_offset == cur_arrival[j].rep_offset) { + exists = 1; + break; + } + } + + if (!exists) { + int z; + + for (z = n; z < nArrivalsPerPosition - 1 && pDestSlots[z].from_slot; z++) { + if (pDestSlots[z].rep_offset == cur_arrival[j].rep_offset) + break; + } + + apultra_arrival* pDestArrival = &pDestSlots[n]; + memmove(&pDestSlots[n + 1], + &pDestSlots[n], + sizeof(apultra_arrival) * (z - n)); + + pDestArrival->cost = nCodingChoiceCost; + pDestArrival->from_pos = i; + pDestArrival->from_slot = j + 1; + pDestArrival->follows_literal = 1; + pDestArrival->rep_offset = cur_arrival[j].rep_offset; + pDestArrival->short_offset = nShortOffset; + pDestArrival->rep_pos = cur_arrival[j].rep_pos; + pDestArrival->match_len = nShortLen; + pDestArrival->score = nScore; + } + } + } + } + } + } + + if (i == nStartOffset && (nBlockFlags & 1)) continue; + + apultra_match *match = pCompressor->match + ((i - nStartOffset) << MATCHES_PER_INDEX_SHIFT); + unsigned short *match_depth = pCompressor->match_depth + ((i - nStartOffset) << MATCHES_PER_INDEX_SHIFT); + int nNumArrivalsForThisPos = j, nOverallMinRepLen = 0, nOverallMaxRepLen = 0; + + int nRepLenForArrival[NARRIVALS_PER_POSITION]; + memset(nRepLenForArrival, 0, NARRIVALS_PER_POSITION * sizeof(int)); + + int nRepMatchArrivalIdx[NARRIVALS_PER_POSITION + 1]; + int nNumRepMatchArrivals = 0; + + int nMaxRepLenForPos = nEndOffset - i; + if (nMaxRepLenForPos > LCP_MAX) + nMaxRepLenForPos = LCP_MAX; + const unsigned char* pInWindowStart = pInWindow + i; + const unsigned char* pInWindowMax = pInWindowStart + nMaxRepLenForPos; + + for (j = 0; j < nNumArrivalsForThisPos && (i + 2) <= nEndOffset; j++) { + int nRepOffset = cur_arrival[j].rep_offset; + + if (cur_arrival[j].follows_literal && + nRepOffset) { + if (i >= nRepOffset) { + + if (pInWindowStart[0] == pInWindowStart[-nRepOffset]) { + const unsigned char* pInWindowAtRepOffset = pInWindowStart; + + int nLen0 = rle_end[i - nRepOffset] - (i - nRepOffset); + int nLen1 = rle_end[i] - (i); + int nMinLen = (nLen0 < nLen1) ? nLen0 : nLen1; + + if (nMinLen > nMaxRepLenForPos) + nMinLen = nMaxRepLenForPos; + pInWindowAtRepOffset += nMinLen; + + while ((pInWindowAtRepOffset + 8) < pInWindowMax && !memcmp(pInWindowAtRepOffset, pInWindowAtRepOffset - nRepOffset, 8)) + pInWindowAtRepOffset += 8; + while ((pInWindowAtRepOffset + 4) < pInWindowMax && !memcmp(pInWindowAtRepOffset, pInWindowAtRepOffset - nRepOffset, 4)) + pInWindowAtRepOffset += 4; + while (pInWindowAtRepOffset < pInWindowMax && pInWindowAtRepOffset[0] == pInWindowAtRepOffset[-nRepOffset]) + pInWindowAtRepOffset++; + + int nCurMaxLen = (int)(pInWindowAtRepOffset - pInWindowStart); + + if (nCurMaxLen >= 2) { + nRepLenForArrival[j] = nCurMaxLen; + nRepMatchArrivalIdx[nNumRepMatchArrivals++] = j; + } + + if (nOverallMaxRepLen < nCurMaxLen) + nOverallMaxRepLen = nCurMaxLen; + } + } + } + } + nRepMatchArrivalIdx[nNumRepMatchArrivals++] = -1; + + for (m = 0; m < NMATCHES_PER_INDEX && match[m].length; m++) { + const int nOrigMatchLen = match[m].length; + const int nOrigMatchOffset = match[m].offset; + const unsigned int nOrigMatchDepth = match_depth[m] & 0x7fff; + const int nScorePenalty = 3 + ((match_depth[m] & 0x8000) >> 15); + unsigned int d; + + for (d = 0; d <= nOrigMatchDepth; d += (nOrigMatchDepth ? nOrigMatchDepth : 1)) { + const int nMatchOffset = nOrigMatchOffset - d; + int nMatchLen = nOrigMatchLen - d; + + if ((i + nMatchLen) > nEndOffset) + nMatchLen = nEndOffset - i; + + if (nInsertForwardReps) { + apultra_insert_forward_match(pCompressor, pInWindow, i, nMatchOffset, nStartOffset, nEndOffset, nArrivalsPerPosition, 0); + } + + if (nMatchLen >= 2) { + int nStartingMatchLen, nJumpMatchLen, k; + int nNoRepMatchOffsetCostForLit[2], nNoRepMatchOffsetCostDelta; + int nMinMatchLenForOffset; + int nNoRepCostAdjusment = (nMatchLen >= LCP_MAX) ? 1 : 0; + + if (nMatchOffset < MINMATCH3_OFFSET) + nMinMatchLenForOffset = 2; + else { + if (nMatchOffset < MINMATCH4_OFFSET) + nMinMatchLenForOffset = 3; + else + nMinMatchLenForOffset = 4; + } + + if (nMatchLen >= LEAVE_ALONE_MATCH_SIZE && i >= nMatchLen) + nStartingMatchLen = nMatchLen; + else + nStartingMatchLen = 2; + + if ((nBlockFlags & 3) == 3 && nMatchLen > 90 && i >= 90) + nJumpMatchLen = 90; + else + nJumpMatchLen = nMatchLen + 1; + + if (nStartingMatchLen <= 3 && nMatchOffset < 128) { + nNoRepMatchOffsetCostForLit[0] = 8 + TOKEN_SIZE_7BIT_MATCH; + nNoRepMatchOffsetCostForLit[1] = 8 + TOKEN_SIZE_7BIT_MATCH; + } + else { + nNoRepMatchOffsetCostForLit[0] = 8 + TOKEN_SIZE_LARGE_MATCH + apultra_get_gamma2_size((nMatchOffset >> 8) + 2); + nNoRepMatchOffsetCostForLit[1] = 8 + TOKEN_SIZE_LARGE_MATCH + apultra_get_gamma2_size((nMatchOffset >> 8) + 3); + } + nNoRepMatchOffsetCostDelta = nNoRepMatchOffsetCostForLit[1] - nNoRepMatchOffsetCostForLit[0]; + + for (k = nStartingMatchLen; k <= nMatchLen; k++) { + int nRepMatchMatchLenCost = apultra_get_gamma2_size(k); + apultra_arrival *pDestSlots = &cur_arrival[k * nArrivalsPerPosition]; + + /* Insert non-repmatch candidate */ + + if (k >= nMinMatchLenForOffset) { + int nNoRepMatchMatchLenCost; + + if (k <= 3 && nMatchOffset < 128) + nNoRepMatchMatchLenCost = 0; + else { + if (nMatchOffset < 128 || nMatchOffset >= MINMATCH4_OFFSET) + nNoRepMatchMatchLenCost = apultra_get_gamma2_size(k - 2); + else if (nMatchOffset < MINMATCH3_OFFSET) + nNoRepMatchMatchLenCost = nRepMatchMatchLenCost; + else + nNoRepMatchMatchLenCost = apultra_get_gamma2_size(k - 1); + } + + for (j = 0; j < nNumArrivalsForThisPos; j++) { + if (nMatchOffset != cur_arrival[j].rep_offset || cur_arrival[j].follows_literal == 0) { + int nPrevCost = cur_arrival[j].cost & 0x3fffffff; + int nMatchCmdCost = nNoRepMatchMatchLenCost + nNoRepMatchOffsetCostForLit[cur_arrival[j].follows_literal]; + int nCodingChoiceCost = nPrevCost + nMatchCmdCost; + + if (nCodingChoiceCost <= (pDestSlots[nArrivalsPerPosition - 1].cost + 1)) { + int nScore = cur_arrival[j].score + nScorePenalty; + + if (nCodingChoiceCost < pDestSlots[nArrivalsPerPosition - 2].cost || + (nCodingChoiceCost == pDestSlots[nArrivalsPerPosition - 2].cost && nScore < pDestSlots[nArrivalsPerPosition - 2].score)) { + int exists = 0; + + for (n = 0; + n < nArrivalsPerPosition && pDestSlots[n].cost < nCodingChoiceCost; + n++) { + if (pDestSlots[n].rep_offset == nMatchOffset) { + exists = 1; + break; + } + } + + if (!exists) { + int nRevisedCodingChoiceCost = nCodingChoiceCost - nNoRepCostAdjusment; + + for (; + n < nArrivalsPerPosition - 1 && pDestSlots[n].cost == nRevisedCodingChoiceCost && nScore >= pDestSlots[n].score; + n++) { + if (pDestSlots[n].rep_offset == nMatchOffset) { + exists = 1; + break; + } + } + + if (!exists) { + if (n < nArrivalsPerPosition - 1) { + int nn; + + for (nn = n; + nn < nArrivalsPerPosition && pDestSlots[nn].cost == nCodingChoiceCost; + nn++) { + if (pDestSlots[nn].rep_offset == nMatchOffset) { + exists = 1; + break; + } + } + + if (!exists) { + int z; + + for (z = n; z < nArrivalsPerPosition - 1 && pDestSlots[z].from_slot; z++) { + if (pDestSlots[z].rep_offset == nMatchOffset) + break; + } + + apultra_arrival* pDestArrival = &pDestSlots[n]; + memmove(&pDestSlots[n + 1], + &pDestSlots[n], + sizeof(apultra_arrival) * (z - n)); + + pDestArrival->cost = nRevisedCodingChoiceCost; + pDestArrival->from_pos = i; + pDestArrival->from_slot = j + 1; + pDestArrival->follows_literal = 0; + pDestArrival->rep_offset = nMatchOffset; + pDestArrival->short_offset = 0; + pDestArrival->rep_pos = i; + pDestArrival->match_len = k; + pDestArrival->score = nScore; + } + } + } + } + else { + if ((nCodingChoiceCost - pDestSlots[n].cost) >= nNoRepMatchOffsetCostDelta) + break; + } + } + if (cur_arrival[j].follows_literal == 0 || nNoRepMatchOffsetCostDelta == 0) + break; + } + else { + break; + } + } + } + } + + /* Insert repmatch candidate */ + + if (k > nOverallMinRepLen && k <= nOverallMaxRepLen) { + int nRepMatchCmdCost = TOKEN_SIZE_LARGE_MATCH + 2 /* apultra_get_gamma2_size(2) */ + nRepMatchMatchLenCost; + int nCurRepMatchArrival; + + if (k <= 90) + nOverallMinRepLen = k; + + for (nCurRepMatchArrival = 0; (j = nRepMatchArrivalIdx[nCurRepMatchArrival]) >= 0; nCurRepMatchArrival++) { + if (nRepLenForArrival[j] >= k) { + int nPrevCost = cur_arrival[j].cost & 0x3fffffff; + int nRepCodingChoiceCost = nPrevCost + nRepMatchCmdCost; + int nScore = cur_arrival[j].score + 2; + + if (nRepCodingChoiceCost < pDestSlots[nArrivalsPerPosition - 1].cost || + (nRepCodingChoiceCost == pDestSlots[nArrivalsPerPosition - 1].cost && nScore < pDestSlots[nArrivalsPerPosition - 1].score)) { + int nRepOffset = cur_arrival[j].rep_offset; + int exists = 0; + + for (n = 0; + n < nArrivalsPerPosition && pDestSlots[n].cost < nRepCodingChoiceCost; + n++) { + if (pDestSlots[n].rep_offset == nRepOffset) { + exists = 1; + break; + } + } + + if (!exists) { + for (; + n < nArrivalsPerPosition && pDestSlots[n].cost == nRepCodingChoiceCost && nScore >= pDestSlots[n].score; + n++) { + if (pDestSlots[n].rep_offset == nRepOffset) { + exists = 1; + break; + } + } + + if (!exists) { + if (n < nArrivalsPerPosition) { + int nn; + + for (nn = n; + nn < nArrivalsPerPosition && pDestSlots[nn].cost == nRepCodingChoiceCost; + nn++) { + if (pDestSlots[nn].rep_offset == nRepOffset) { + exists = 1; + break; + } + } + + if (!exists) { + int z; + + for (z = n; z < nArrivalsPerPosition - 1 && pDestSlots[z].from_slot; z++) { + if (pDestSlots[z].rep_offset == nRepOffset) + break; + } + + apultra_arrival* pDestArrival = &pDestSlots[n]; + memmove(&pDestSlots[n + 1], + &pDestSlots[n], + sizeof(apultra_arrival) * (z - n)); + + pDestArrival->cost = nRepCodingChoiceCost; + pDestArrival->from_pos = i; + pDestArrival->from_slot = j + 1; + pDestArrival->follows_literal = 0; + pDestArrival->rep_offset = nRepOffset; + pDestArrival->short_offset = 0; + pDestArrival->rep_pos = i; + pDestArrival->match_len = k; + pDestArrival->score = nScore; + } + } + } + } + } + else { + break; + } + } + } + } + + if (k == 3 && nMatchOffset < 128) { + nNoRepMatchOffsetCostForLit[0] = 8 + TOKEN_SIZE_LARGE_MATCH + 2 /* apultra_get_gamma2_size((nMatchOffset >> 8) + 2) */; + nNoRepMatchOffsetCostForLit[1] = 8 + TOKEN_SIZE_LARGE_MATCH + 2 /* apultra_get_gamma2_size((nMatchOffset >> 8) + 3) */; + } + + if (k == nJumpMatchLen) + k = nMatchLen - 1; + } + } + + if (nOrigMatchLen >= 512) + break; + } + } + } + + if (!nInsertForwardReps) { + apultra_arrival* end_arrival = &arrival[(i * nArrivalsPerPosition) + 0]; + apultra_final_match* pBestMatch = pCompressor->best_match - nStartOffset; + + while (end_arrival->from_slot > 0 && end_arrival->from_pos >= 0 && (int)end_arrival->from_pos < nEndOffset) { + pBestMatch[end_arrival->from_pos].length = end_arrival->match_len; + if (end_arrival->match_len >= 2) + pBestMatch[end_arrival->from_pos].offset = end_arrival->rep_offset; + else + pBestMatch[end_arrival->from_pos].offset = end_arrival->short_offset; + + end_arrival = &arrival[(end_arrival->from_pos * nArrivalsPerPosition) + (end_arrival->from_slot - 1)]; + } + } +} + +/** + * Attempt to replace matches by literals when it makes the final bitstream smaller, and merge large matches + * + * @param pCompressor compression context + * @param pInWindow pointer to input data window (previously compressed bytes + bytes to compress) + * @param pBestMatch optimal matches to evaluate and update + * @param nStartOffset current offset in input window (typically the number of previously compressed bytes) + * @param nEndOffset offset to end finding matches at (typically the size of the total input window in bytes + * @param nCurRepMatchOffset starting rep offset for this block + * @param nBlockFlags bit 0: 1 for first block, 0 otherwise; bit 1: 1 for last block, 0 otherwise + * + * @return non-zero if the number of tokens was reduced, 0 if it wasn't + */ +static int apultra_reduce_commands(apultra_compressor *pCompressor, const unsigned char *pInWindow, apultra_final_match *pBestMatch, const int nStartOffset, const int nEndOffset, const int *nCurRepMatchOffset, const int nBlockFlags) { + int i; + int nRepMatchOffset = *nCurRepMatchOffset; + int nFollowsLiteral = 0; + int nDidReduce = 0; + int nLastMatchLen = 0; + const unsigned char *match1 = pCompressor->match1 - nStartOffset; + + for (i = nStartOffset + ((nBlockFlags & 1) ? 1 : 0); i < nEndOffset; ) { + apultra_final_match *pMatch = pBestMatch + i; + + if (pMatch->length <= 1 && + (i + 1) < nEndOffset && + pBestMatch[i + 1].length >= 2 && + pBestMatch[i + 1].length < MAX_VARLEN && + pBestMatch[i + 1].offset && + i >= pBestMatch[i + 1].offset && + (i + pBestMatch[i + 1].length + 1) <= nEndOffset && + !memcmp(pInWindow + i - (pBestMatch[i + 1].offset), pInWindow + i, pBestMatch[i + 1].length + 1)) { + if ((pBestMatch[i + 1].offset < MINMATCH3_OFFSET || (pBestMatch[i + 1].length + 1) >= 3 || (pBestMatch[i + 1].offset == nRepMatchOffset && nFollowsLiteral)) && + (pBestMatch[i + 1].offset < MINMATCH4_OFFSET || (pBestMatch[i + 1].length + 1) >= 4 || (pBestMatch[i + 1].offset == nRepMatchOffset && nFollowsLiteral))) { + + int nCurPartialCommandSize = (pMatch->length == 1) ? (TOKEN_SIZE_4BIT_MATCH + 4) : (1 /* literal bit */ + 8 /* literal size */); + if (pBestMatch[i + 1].offset == nRepMatchOffset /* always follows a literal, the one at the current position */) { + nCurPartialCommandSize += TOKEN_SIZE_LARGE_MATCH + 2 /* apultra_get_gamma2_size(2) */ + apultra_get_gamma2_size(pBestMatch[i + 1].length); + } + else { + nCurPartialCommandSize += apultra_get_offset_varlen_size(pBestMatch[i + 1].length, pBestMatch[i + 1].offset, 1) + apultra_get_match_varlen_size(pBestMatch[i + 1].length, pBestMatch[i + 1].offset); + } + + int nReducedPartialCommandSize; + if (pBestMatch[i + 1].offset == nRepMatchOffset && nFollowsLiteral) { + nReducedPartialCommandSize = TOKEN_SIZE_LARGE_MATCH + 2 /* apultra_get_gamma2_size(2) */ + apultra_get_gamma2_size(pBestMatch[i + 1].length); + } + else { + nReducedPartialCommandSize = apultra_get_offset_varlen_size(pBestMatch[i + 1].length, pBestMatch[i + 1].offset, nFollowsLiteral) + apultra_get_match_varlen_size(pBestMatch[i + 1].length, pBestMatch[i + 1].offset); + } + + if (nReducedPartialCommandSize < nCurPartialCommandSize || (nFollowsLiteral == 0 && nLastMatchLen >= LCP_MAX)) { + /* Merge */ + pBestMatch[i].length = pBestMatch[i + 1].length + 1; + pBestMatch[i].offset = pBestMatch[i + 1].offset; + pBestMatch[i + 1].length = 0; + pBestMatch[i + 1].offset = 0; + nDidReduce = 1; + continue; + } + } + } + + if (pMatch->length >= 2) { + if (pMatch->length < 32 && /* Don't waste time considering large matches, they will always win over literals */ + (i + pMatch->length) < nEndOffset /* Don't consider the last match in the block, we can only reduce a match inbetween other tokens */) { + int nNextIndex = i + pMatch->length; + int nNextFollowsLiteral = 0; + int nCannotEncode = 0; + + while (nNextIndex < nEndOffset && pBestMatch[nNextIndex].length < 2) { + nNextIndex++; + nNextFollowsLiteral = 1; + } + + if (nNextIndex < nEndOffset && pBestMatch[nNextIndex].length >= 2) { + if (nRepMatchOffset && nRepMatchOffset != pMatch->offset && pBestMatch[nNextIndex].offset && pMatch->offset != pBestMatch[nNextIndex].offset && + nNextFollowsLiteral) { + /* Try to gain a match forward */ + if (i >= pBestMatch[nNextIndex].offset && (i - pBestMatch[nNextIndex].offset + pMatch->length) <= nEndOffset) { + if ((pBestMatch[nNextIndex].offset < MINMATCH3_OFFSET || pMatch->length >= 3) && + (pBestMatch[nNextIndex].offset < MINMATCH4_OFFSET || pMatch->length >= 4)) { + int nMaxLen = 0; + const unsigned char* pInWindowAtPos = pInWindow + i; + while (nMaxLen < pMatch->length && pInWindowAtPos[nMaxLen - pBestMatch[nNextIndex].offset] == pInWindowAtPos[nMaxLen]) + nMaxLen++; + + if (nMaxLen >= pMatch->length) { + /* Replace */ + pMatch->offset = pBestMatch[nNextIndex].offset; + nDidReduce = 1; + } + else if (nMaxLen >= 2) { + if ((nFollowsLiteral && nRepMatchOffset == pBestMatch[nNextIndex].offset) || + ((pBestMatch[nNextIndex].offset < MINMATCH3_OFFSET || nMaxLen >= 3) && + (pBestMatch[nNextIndex].offset < MINMATCH4_OFFSET || nMaxLen >= 4))) { + + int nPartialSizeBefore, nPartialSizeAfter, j; + + nPartialSizeBefore = apultra_get_offset_varlen_size(pMatch->length, pMatch->offset, nFollowsLiteral); + nPartialSizeBefore += apultra_get_match_varlen_size(pMatch->length, pMatch->offset); + + nPartialSizeBefore += apultra_get_offset_varlen_size(pBestMatch[nNextIndex].length, pBestMatch[nNextIndex].offset, 1); + nPartialSizeBefore += apultra_get_match_varlen_size(pBestMatch[nNextIndex].length, pBestMatch[nNextIndex].offset); + + nPartialSizeAfter = apultra_get_offset_varlen_size(nMaxLen, pBestMatch[nNextIndex].offset, nFollowsLiteral); + if (nFollowsLiteral && nRepMatchOffset == pBestMatch[nNextIndex].offset) + nPartialSizeAfter += apultra_get_gamma2_size(nMaxLen); + else + nPartialSizeAfter += apultra_get_match_varlen_size(nMaxLen, pBestMatch[nNextIndex].offset); + + nPartialSizeAfter += TOKEN_SIZE_LARGE_MATCH + 2 /* apultra_get_gamma2_size(2) */; + nPartialSizeAfter += apultra_get_gamma2_size(pBestMatch[nNextIndex].length); + + for (j = nMaxLen; j < pMatch->length; j++) { + if (pInWindow[i + j] == 0 || match1[i + j]) + nPartialSizeAfter += TOKEN_SIZE_4BIT_MATCH + 4; + else + nPartialSizeAfter += 1 /* literal bit */ + 8 /* literal byte */; + } + + if (nPartialSizeAfter < nPartialSizeBefore) { + /* We gain a repmatch that is shorter than the original match as this is the best we can do, so it is followed by extra literals, but + * we have calculated that this is shorter */ + + int nOrigLen = pMatch->length; + int j; + + pMatch->offset = pBestMatch[nNextIndex].offset; + pMatch->length = nMaxLen; + + for (j = nMaxLen; j < nOrigLen; j++) { + pBestMatch[i + j].offset = match1[i + j]; + pBestMatch[i + j].length = (pInWindow[i + j] && match1[i+j] == 0) ? 0 : 1; + } + + nDidReduce = 1; + continue; + } + } + } + } + } + } + + /* Calculate this command's current cost */ + + int nCurCommandSize; + if (pMatch->offset == nRepMatchOffset && nFollowsLiteral) { + nCurCommandSize = TOKEN_SIZE_LARGE_MATCH + 2 /* apultra_get_gamma2_size(2) */ + apultra_get_gamma2_size(pMatch->length); + } + else { + nCurCommandSize = apultra_get_offset_varlen_size(pMatch->length, pMatch->offset, nFollowsLiteral) + apultra_get_match_varlen_size(pMatch->length, pMatch->offset); + } + + /* Calculate the next command's current cost */ + int nNextCommandSize; + if (pBestMatch[nNextIndex].offset == pMatch->offset && nNextFollowsLiteral && pBestMatch[nNextIndex].length >= 2) { + nNextCommandSize = TOKEN_SIZE_LARGE_MATCH + 2 /* apultra_get_gamma2_size(2) */ + apultra_get_gamma2_size(pBestMatch[nNextIndex].length); + } + else { + nNextCommandSize = apultra_get_offset_varlen_size(pBestMatch[nNextIndex].length, pBestMatch[nNextIndex].offset, nNextFollowsLiteral) + apultra_get_match_varlen_size(pBestMatch[nNextIndex].length, pBestMatch[nNextIndex].offset); + } + + int nOriginalCombinedCommandSize = nCurCommandSize + nNextCommandSize; + + /* Calculate the cost of replacing this match command by literals + the effect on the cost of the next command */ + int nReducedCommandSize = 0; + int j; + + for (j = 0; j < pMatch->length; j++) { + if (pInWindow[i + j] == 0 || match1[i + j]) + nReducedCommandSize += TOKEN_SIZE_4BIT_MATCH + 4; + else + nReducedCommandSize += 1 /* literal bit */ + 8; + } + + if (pBestMatch[nNextIndex].offset == nRepMatchOffset /* the new command would always follow literals, the ones we create */ && pBestMatch[nNextIndex].length >= 2) { + nReducedCommandSize += TOKEN_SIZE_LARGE_MATCH + 2 /* apultra_get_gamma2_size(2) */ + apultra_get_gamma2_size(pBestMatch[nNextIndex].length); + } + else { + if ((pBestMatch[nNextIndex].length < 3 && pBestMatch[nNextIndex].offset >= MINMATCH3_OFFSET) || + (pBestMatch[nNextIndex].length < 4 && pBestMatch[nNextIndex].offset >= MINMATCH4_OFFSET)) { + /* This match length can only be encoded with a rep-match */ + nCannotEncode = 1; + } + else { + nReducedCommandSize += apultra_get_offset_varlen_size(pBestMatch[nNextIndex].length, pBestMatch[nNextIndex].offset, 1 /* follows literals */) + apultra_get_match_varlen_size(pBestMatch[nNextIndex].length, pBestMatch[nNextIndex].offset); + } + } + + if (!nCannotEncode && nOriginalCombinedCommandSize > nReducedCommandSize) { + /* Reduce */ + int nMatchLen = pMatch->length; + int j; + + for (j = 0; j < nMatchLen; j++) { + pBestMatch[i + j].offset = match1[i + j]; + pBestMatch[i + j].length = (pInWindow[i + j] && match1[i + j] == 0) ? 0 : 1; + } + + nDidReduce = 1; + continue; + } + } + } + + if ((i + pMatch->length) < nEndOffset && pMatch->offset > 0 && + pBestMatch[i + pMatch->length].offset > 0 && + pBestMatch[i + pMatch->length].length >= 2 && + (pMatch->length + pBestMatch[i + pMatch->length].length) >= LEAVE_ALONE_MATCH_SIZE && + (pMatch->length + pBestMatch[i + pMatch->length].length) <= MAX_VARLEN && + (i + pMatch->length) >= pMatch->offset && + (i + pMatch->length) >= pBestMatch[i + pMatch->length].offset && + (i + pMatch->length + pBestMatch[i + pMatch->length].length) <= nEndOffset && + !memcmp(pInWindow + i + pMatch->length - pMatch->offset, + pInWindow + i + pMatch->length - pBestMatch[i + pMatch->length].offset, + pBestMatch[i + pMatch->length].length)) { + int nMatchLen = pMatch->length; + + /* Join large matches */ + + int nNextIndex = i + pMatch->length + pBestMatch[i + pMatch->length].length; + int nNextFollowsLiteral = 0; + int nCannotEncode = 0; + + while (nNextIndex < nEndOffset && pBestMatch[nNextIndex].length < 2) { + nNextIndex++; + nNextFollowsLiteral = 1; + } + + if (nNextIndex < nEndOffset && nNextFollowsLiteral && pBestMatch[nNextIndex].length >= 2 && + pBestMatch[nNextIndex].offset == pBestMatch[i + pMatch->length].offset) { + if ((pBestMatch[nNextIndex].offset >= MINMATCH3_OFFSET && pBestMatch[nNextIndex].length < 3) || + (pBestMatch[nNextIndex].offset >= MINMATCH4_OFFSET && pBestMatch[nNextIndex].length < 4)) { + nCannotEncode = 1; + } + } + + if (!nCannotEncode) { + pMatch->length += pBestMatch[i + nMatchLen].length; + pBestMatch[i + nMatchLen].offset = 0; + pBestMatch[i + nMatchLen].length = -1; + nDidReduce = 1; + continue; + } + } + + nRepMatchOffset = pMatch->offset; + nFollowsLiteral = 0; + nLastMatchLen = pMatch->length; + + i += pMatch->length; + } + else { + /* 4 bits offset (1 byte match) or literal */ + i++; + nFollowsLiteral = 1; + nLastMatchLen = 0; + } + } + + return nDidReduce; +} + +/** + * Emit a block of compressed data + * + * @param pCompressor compression context + * @param pBestMatch optimal matches to emit + * @param pInWindow pointer to input data window (previously compressed bytes + bytes to compress) + * @param nStartOffset current offset in input window (typically the number of previously compressed bytes) + * @param nEndOffset offset to end finding matches at (typically the size of the total input window in bytes + * @param pOutData pointer to output buffer + * @param nMaxOutDataSize maximum size of output buffer, in bytes + * @param nCurBitsOffset write index into output buffer, of current byte being filled with bits + * @param nCurBitShift bit shift count + * @param nFollowsLiteral non-zero if the next command to be issued follows a literal, 0 if not + * @param nCurRepMatchOffset starting rep offset for this block, updated after the block is compressed successfully + * @param nBlockFlags bit 0: 1 for first block, 0 otherwise; bit 1: 1 for last block, 0 otherwise + * + * @return size of compressed data in output buffer, or -1 if the data is uncompressible + */ +static int apultra_write_block(apultra_compressor *pCompressor, apultra_final_match *pBestMatch, const unsigned char *pInWindow, const int nStartOffset, const int nEndOffset, unsigned char *pOutData, int nOutOffset, const int nMaxOutDataSize, int *nCurBitsOffset, int *nCurBitShift, int *nFollowsLiteral, int *nCurRepMatchOffset, const int nBlockFlags) { + int i; + int nRepMatchOffset = *nCurRepMatchOffset; + const int nMaxOffset = pCompressor->max_offset; + + if (nBlockFlags & 1) { + if (nOutOffset < 0 || nOutOffset >= nMaxOutDataSize) + return -1; + pOutData[nOutOffset++] = pInWindow[nStartOffset]; + *nFollowsLiteral = 1; + } + + for (i = nStartOffset + ((nBlockFlags & 1) ? 1 : 0); i < nEndOffset; ) { + const apultra_final_match *pMatch = pBestMatch + i; + + if (pMatch->length >= 2) { + int nMatchOffset = pMatch->offset; + int nMatchLen = pMatch->length; + + if (nMatchOffset < MIN_OFFSET || nMatchOffset > nMaxOffset) + return -1; + + if (nMatchOffset == nRepMatchOffset && *nFollowsLiteral) { + /* Rep-match */ + nOutOffset = apultra_write_bits(pOutData, nOutOffset, nMaxOutDataSize, TOKEN_CODE_LARGE_MATCH, TOKEN_SIZE_LARGE_MATCH, nCurBitsOffset, nCurBitShift); + nOutOffset = apultra_write_bits(pOutData, nOutOffset, nMaxOutDataSize, 0 /* length of 2 encoded as gamma 2 */, 2, nCurBitsOffset, nCurBitShift); + + /* The match length isn't encoded in the command, emit elias gamma value */ + nOutOffset = apultra_write_gamma2_value(pOutData, nOutOffset, nMaxOutDataSize, nMatchLen, nCurBitsOffset, nCurBitShift); + if (nOutOffset < 0) return -1; + + *nFollowsLiteral = 0; + + pCompressor->stats.num_rep_matches++; + } + else { + if (nMatchLen <= 3 && nMatchOffset < 128) { + /* 7 bits offset + 1 bit length */ + nOutOffset = apultra_write_bits(pOutData, nOutOffset, nMaxOutDataSize, TOKEN_CODE_7BIT_MATCH, TOKEN_SIZE_7BIT_MATCH, nCurBitsOffset, nCurBitShift); + + if (nOutOffset < 0 || nOutOffset >= nMaxOutDataSize) + return -1; + pOutData[nOutOffset++] = ((nMatchOffset) & 0x7f) << 1 | (nMatchLen - 2); + + *nFollowsLiteral = 0; + nRepMatchOffset = nMatchOffset; + + pCompressor->stats.num_7bit_matches++; + } + else { + /* 8+n bits offset */ + nOutOffset = apultra_write_bits(pOutData, nOutOffset, nMaxOutDataSize, TOKEN_CODE_LARGE_MATCH, TOKEN_SIZE_LARGE_MATCH, nCurBitsOffset, nCurBitShift); + + if (nOutOffset < 0 || nOutOffset >= nMaxOutDataSize) + return -1; + if (*nFollowsLiteral) + nOutOffset = apultra_write_gamma2_value(pOutData, nOutOffset, nMaxOutDataSize, (nMatchOffset >> 8) + 3, nCurBitsOffset, nCurBitShift); + else + nOutOffset = apultra_write_gamma2_value(pOutData, nOutOffset, nMaxOutDataSize, (nMatchOffset >> 8) + 2, nCurBitsOffset, nCurBitShift); + pOutData[nOutOffset++] = nMatchOffset & 0xff; + + /* The match length isn't encoded in the command, emit elias gamma value */ + + if (nMatchOffset < 128 || nMatchOffset >= MINMATCH4_OFFSET) + nOutOffset = apultra_write_gamma2_value(pOutData, nOutOffset, nMaxOutDataSize, nMatchLen - 2, nCurBitsOffset, nCurBitShift); + else if (nMatchOffset < MINMATCH3_OFFSET) + nOutOffset = apultra_write_gamma2_value(pOutData, nOutOffset, nMaxOutDataSize, nMatchLen, nCurBitsOffset, nCurBitShift); + else + nOutOffset = apultra_write_gamma2_value(pOutData, nOutOffset, nMaxOutDataSize, nMatchLen - 1, nCurBitsOffset, nCurBitShift); + if (nOutOffset < 0) return -1; + + *nFollowsLiteral = 0; + nRepMatchOffset = nMatchOffset; + + pCompressor->stats.num_variable_matches++; + } + } + + if (nMatchOffset < pCompressor->stats.min_offset || pCompressor->stats.min_offset == -1) + pCompressor->stats.min_offset = nMatchOffset; + if (nMatchOffset > pCompressor->stats.max_offset) + pCompressor->stats.max_offset = nMatchOffset; + pCompressor->stats.total_offsets += (long long)nMatchOffset; + + if (nMatchLen < pCompressor->stats.min_match_len || pCompressor->stats.min_match_len == -1) + pCompressor->stats.min_match_len = nMatchLen; + if (nMatchLen > pCompressor->stats.max_match_len) + pCompressor->stats.max_match_len = nMatchLen; + pCompressor->stats.total_match_lens += nMatchLen; + pCompressor->stats.match_divisor++; + + if (nMatchOffset == 1) { + if (nMatchLen < pCompressor->stats.min_rle1_len || pCompressor->stats.min_rle1_len == -1) + pCompressor->stats.min_rle1_len = nMatchLen; + if (nMatchLen > pCompressor->stats.max_rle1_len) + pCompressor->stats.max_rle1_len = nMatchLen; + pCompressor->stats.total_rle1_lens += nMatchLen; + pCompressor->stats.rle1_divisor++; + } + else if (nMatchOffset == 2) { + if (nMatchLen < pCompressor->stats.min_rle2_len || pCompressor->stats.min_rle2_len == -1) + pCompressor->stats.min_rle2_len = nMatchLen; + if (nMatchLen > pCompressor->stats.max_rle2_len) + pCompressor->stats.max_rle2_len = nMatchLen; + pCompressor->stats.total_rle2_lens += nMatchLen; + pCompressor->stats.rle2_divisor++; + } + + i += nMatchLen; + + pCompressor->stats.commands_divisor++; + } + else if (pMatch->length == 1) { + int nMatchOffset = pMatch->offset; + + /* 4 bits offset */ + + if (nMatchOffset < 0 || nMatchOffset > 15) + return -1; + + nOutOffset = apultra_write_bits(pOutData, nOutOffset, nMaxOutDataSize, TOKEN_CODE_4BIT_MATCH, TOKEN_SIZE_4BIT_MATCH, nCurBitsOffset, nCurBitShift); + nOutOffset = apultra_write_bits(pOutData, nOutOffset, nMaxOutDataSize, nMatchOffset, 4, nCurBitsOffset, nCurBitShift); + if (nOutOffset < 0) return -1; + + pCompressor->stats.num_4bit_matches++; + pCompressor->stats.commands_divisor++; + + i++; + *nFollowsLiteral = 1; + } + else { + /* Literal */ + + nOutOffset = apultra_write_bits(pOutData, nOutOffset, nMaxOutDataSize, 0 /* literal */, 1, nCurBitsOffset, nCurBitShift); + + if (nOutOffset < 0 || nOutOffset >= nMaxOutDataSize) + return -1; + pOutData[nOutOffset++] = pInWindow[i]; + + pCompressor->stats.num_literals++; + pCompressor->stats.commands_divisor++; + i++; + *nFollowsLiteral = 1; + } + + int nCurSafeDist = (i - nStartOffset) - nOutOffset; + if (nCurSafeDist >= 0 && pCompressor->stats.safe_dist < nCurSafeDist) + pCompressor->stats.safe_dist = nCurSafeDist; + } + + if (nBlockFlags & 2) { + /* 8 bits offset */ + + nOutOffset = apultra_write_bits(pOutData, nOutOffset, nMaxOutDataSize, TOKEN_CODE_7BIT_MATCH, TOKEN_SIZE_7BIT_MATCH, nCurBitsOffset, nCurBitShift); + + if (nOutOffset < 0 || nOutOffset >= nMaxOutDataSize) + return -1; + pOutData[nOutOffset++] = 0x00; /* Offset: EOD */ + pCompressor->stats.num_eod++; + pCompressor->stats.commands_divisor++; + + int nCurSafeDist = (i - nStartOffset) - nOutOffset; + if (nCurSafeDist >= 0 && pCompressor->stats.safe_dist < nCurSafeDist) + pCompressor->stats.safe_dist = nCurSafeDist; + } + + *nCurRepMatchOffset = nRepMatchOffset; + return nOutOffset; +} + +/** + * Select the most optimal matches, reduce the token count if possible, and then emit a block of compressed data + * + * @param pCompressor compression context + * @param pInWindow pointer to input data window (previously compressed bytes + bytes to compress) + * @param nPreviousBlockSize number of previously compressed bytes (or 0 for none) + * @param nInDataSize number of input bytes to compress + * @param pOutData pointer to output buffer + * @param nMaxOutDataSize maximum size of output buffer, in bytes + * @param nCurBitsOffset write index into output buffer, of current byte being filled with bits + * @param nCurBitShift bit shift count + * @param nCurFollowsLiteral non-zero if the next command to be issued follows a literal, 0 if not + * @param nCurRepMatchOffset starting rep offset for this block, updated after the block is compressed successfully + * @param nBlockFlags bit 0: 1 for first block, 0 otherwise; bit 1: 1 for last block, 0 otherwise + * + * @return size of compressed data in output buffer, or -1 if the data is uncompressible + */ +static int apultra_optimize_and_write_block(apultra_compressor *pCompressor, const unsigned char *pInWindow, const int nPreviousBlockSize, const int nInDataSize, unsigned char *pOutData, const int nMaxOutDataSize, int *nCurBitsOffset, int *nCurBitShift, int *nCurFollowsLiteral, int *nCurRepMatchOffset, const int nBlockFlags) { + int nOutOffset = 0; + const int nArrivalsPerPosition = pCompressor->max_arrivals; + int *rle_end = (int*)pCompressor->intervals /* reuse */; + int i, nPosition; + + memset(pCompressor->best_match, 0, pCompressor->block_size * sizeof(apultra_final_match)); + + if ((nBlockFlags & 3) == 3) { + int *first_offset_for_byte = pCompressor->first_offset_for_byte; + int *next_offset_for_pos = pCompressor->next_offset_for_pos; + + /* Supplement 2 and 3-byte matches */ + + memset(first_offset_for_byte, 0xff, sizeof(int) * 65536); + memset(next_offset_for_pos, 0xff, sizeof(int) * nInDataSize); + + for (nPosition = nPreviousBlockSize; nPosition < nPreviousBlockSize + nInDataSize - 1; nPosition++) { + next_offset_for_pos[nPosition - nPreviousBlockSize] = first_offset_for_byte[((unsigned int)pInWindow[nPosition]) | (((unsigned int)pInWindow[nPosition + 1]) << 8)]; + first_offset_for_byte[((unsigned int)pInWindow[nPosition]) | (((unsigned int)pInWindow[nPosition + 1]) << 8)] = nPosition; + } + + for (nPosition = nPreviousBlockSize + 1; nPosition < (nPreviousBlockSize + nInDataSize - 1); nPosition++) { + apultra_match *match = pCompressor->match + ((nPosition - nPreviousBlockSize) << MATCHES_PER_INDEX_SHIFT); + unsigned short *match_depth = pCompressor->match_depth + ((nPosition - nPreviousBlockSize) << MATCHES_PER_INDEX_SHIFT); + int m = 0, nInserted = 0; + int nMatchPos; + + while (m < 15 && match[m].length) + m++; + + for (nMatchPos = next_offset_for_pos[nPosition - nPreviousBlockSize]; m < 15 && nMatchPos >= 0; nMatchPos = next_offset_for_pos[nMatchPos - nPreviousBlockSize]) { + int nMatchOffset = nPosition - nMatchPos; + + if (nMatchOffset <= pCompressor->max_offset) { + int nExistingMatchIdx; + int nAlreadyExists = 0; + + for (nExistingMatchIdx = 0; nExistingMatchIdx < m; nExistingMatchIdx++) { + if (match[nExistingMatchIdx].offset == nMatchOffset || + (match[nExistingMatchIdx].offset - (match_depth[nExistingMatchIdx] & 0x7fff)) == nMatchOffset) { + nAlreadyExists = 1; + break; + } + } + + if (!nAlreadyExists) { + match[m].length = (nPosition < (nPreviousBlockSize + nInDataSize - 2) && pInWindow[nMatchPos + 2] == pInWindow[nPosition + 2]) ? 3 : 2; + match[m].offset = nMatchOffset; + match_depth[m] = 0; + m++; + nInserted++; + if (nInserted >= 6) + break; + } + } + else { + break; + } + } + } + } + + i = 0; + while (i < (nPreviousBlockSize + nInDataSize)) { + int nRangeStartIdx = i; + unsigned char c = pInWindow[nRangeStartIdx]; + do { + i++; + } + while (i < (nPreviousBlockSize + nInDataSize) && pInWindow[i] == c); + while (nRangeStartIdx < i) { + rle_end[nRangeStartIdx++] = i; + } + } + + apultra_optimize_forward(pCompressor, pInWindow, nPreviousBlockSize, nPreviousBlockSize + nInDataSize, 1 /* nInsertForwardReps */, nCurRepMatchOffset, nBlockFlags, nArrivalsPerPosition); + + /* Pick optimal matches */ + apultra_optimize_forward(pCompressor, pInWindow, nPreviousBlockSize, nPreviousBlockSize + nInDataSize, 0 /* nInsertForwardReps */, nCurRepMatchOffset, nBlockFlags, nArrivalsPerPosition); + + /* Apply reduction and merge pass */ + int nDidReduce; + int nPasses = 0; + do { + nDidReduce = apultra_reduce_commands(pCompressor, pInWindow, pCompressor->best_match - nPreviousBlockSize, nPreviousBlockSize, nPreviousBlockSize + nInDataSize, nCurRepMatchOffset, nBlockFlags); + nPasses++; + } while (nDidReduce && nPasses < 20); + + /* Write compressed block */ + + return apultra_write_block(pCompressor, pCompressor->best_match - nPreviousBlockSize, pInWindow, nPreviousBlockSize, nPreviousBlockSize + nInDataSize, pOutData, nOutOffset, nMaxOutDataSize, nCurBitsOffset, nCurBitShift, nCurFollowsLiteral, nCurRepMatchOffset, nBlockFlags); +} + +/* Forward declaration */ +static void apultra_compressor_destroy(apultra_compressor *pCompressor); + +/** + * Initialize compression context + * + * @param pCompressor compression context to initialize + * @param nBlockSize maximum size of input data (bytes to compress only) + * @param nMaxWindowSize maximum size of input data window (previously compressed bytes + bytes to compress) + * @param nMaxArrivals maximum number of arrivals per position + * @param nFlags compression flags + * + * @return 0 for success, non-zero for failure + */ +static int apultra_compressor_init(apultra_compressor *pCompressor, const int nBlockSize, const int nMaxWindowSize, const int nMaxArrivals, const int nFlags) { + int nResult; + + nResult = divsufsort_init(&pCompressor->divsufsort_context); + pCompressor->intervals = NULL; + pCompressor->pos_data = NULL; + pCompressor->open_intervals = NULL; + pCompressor->match = NULL; + pCompressor->match_depth = NULL; + pCompressor->match1 = NULL; + pCompressor->best_match = NULL; + pCompressor->arrival = NULL; + pCompressor->first_offset_for_byte = NULL; + pCompressor->next_offset_for_pos = NULL; + pCompressor->flags = nFlags; + pCompressor->block_size = nBlockSize; + pCompressor->max_arrivals = nMaxArrivals; + + memset(&pCompressor->stats, 0, sizeof(pCompressor->stats)); + pCompressor->stats.min_match_len = -1; + pCompressor->stats.min_offset = -1; + pCompressor->stats.min_rle1_len = -1; + pCompressor->stats.min_rle2_len = -1; + + if (!nResult) { + pCompressor->intervals = (unsigned long long *)malloc(nMaxWindowSize * sizeof(unsigned long long)); + + if (pCompressor->intervals) { + pCompressor->pos_data = (unsigned long long *)malloc(nMaxWindowSize * sizeof(unsigned long long)); + + if (pCompressor->pos_data) { + pCompressor->open_intervals = (unsigned long long *)malloc((LCP_AND_TAG_MAX + 1) * sizeof(unsigned long long)); + + if (pCompressor->open_intervals) { + pCompressor->arrival = (apultra_arrival *)malloc((nBlockSize + 1) * nMaxArrivals * sizeof(apultra_arrival)); + + if (pCompressor->arrival) { + pCompressor->best_match = (apultra_final_match *)malloc(nBlockSize * sizeof(apultra_final_match)); + + if (pCompressor->best_match) { + pCompressor->match = (apultra_match *)malloc(nBlockSize * NMATCHES_PER_INDEX * sizeof(apultra_match)); + if (pCompressor->match) { + pCompressor->match_depth = (unsigned short *)malloc(nBlockSize * NMATCHES_PER_INDEX * sizeof(unsigned short)); + if (pCompressor->match_depth) { + pCompressor->match1 = (unsigned char *)malloc(nBlockSize * sizeof(unsigned char)); + if (pCompressor->match1) { + pCompressor->first_offset_for_byte = (int*)malloc(65536 * sizeof(int)); + if (pCompressor->first_offset_for_byte) { + pCompressor->next_offset_for_pos = (int*)malloc(nBlockSize * sizeof(int)); + if (pCompressor->next_offset_for_pos) { + return 0; + } + } + } + } + } + } + } + } + } + } + } + + apultra_compressor_destroy(pCompressor); + return 100; +} + +/** + * Clean up compression context and free up any associated resources + * + * @param pCompressor compression context to clean up + */ +static void apultra_compressor_destroy(apultra_compressor *pCompressor) { + divsufsort_destroy(&pCompressor->divsufsort_context); + + if (pCompressor->next_offset_for_pos) { + free(pCompressor->next_offset_for_pos); + pCompressor->next_offset_for_pos = NULL; + } + + if (pCompressor->first_offset_for_byte) { + free(pCompressor->first_offset_for_byte); + pCompressor->first_offset_for_byte = NULL; + } + + if (pCompressor->match1) { + free(pCompressor->match1); + pCompressor->match1 = NULL; + } + + if (pCompressor->match_depth) { + free(pCompressor->match_depth); + pCompressor->match_depth = NULL; + } + + if (pCompressor->match) { + free(pCompressor->match); + pCompressor->match = NULL; + } + + if (pCompressor->arrival) { + free(pCompressor->arrival); + pCompressor->arrival = NULL; + } + + if (pCompressor->best_match) { + free(pCompressor->best_match); + pCompressor->best_match = NULL; + } + + if (pCompressor->open_intervals) { + free(pCompressor->open_intervals); + pCompressor->open_intervals = NULL; + } + + if (pCompressor->pos_data) { + free(pCompressor->pos_data); + pCompressor->pos_data = NULL; + } + + if (pCompressor->intervals) { + free(pCompressor->intervals); + pCompressor->intervals = NULL; + } +} + +/** + * Compress one block of data + * + * @param pCompressor compression context + * @param pInWindow pointer to input data window (previously compressed bytes + bytes to compress) + * @param nPreviousBlockSize number of previously compressed bytes (or 0 for none) + * @param nInDataSize number of input bytes to compress + * @param pOutData pointer to output buffer + * @param nMaxOutDataSize maximum size of output buffer, in bytes + * @param nCurBitsOffset write index into output buffer, of current byte being filled with bits + * @param nCurBitShift bit shift count + * @param nCurFollowsLiteral non-zero if the next command to be issued follows a literal, 0 if not + * @param nCurRepMatchOffset starting rep offset for this block, updated after the block is compressed successfully + * @param nBlockFlags bit 0: 1 for first block, 0 otherwise; bit 1: 1 for last block, 0 otherwise + * + * @return size of compressed data in output buffer, or -1 if the data is uncompressible + */ +static int apultra_compressor_shrink_block(apultra_compressor *pCompressor, const unsigned char *pInWindow, const int nPreviousBlockSize, const int nInDataSize, unsigned char *pOutData, const int nMaxOutDataSize, int *nCurBitsOffset, int *nCurBitShift, int *nCurFollowsLiteral, int *nCurRepMatchOffset, const int nBlockFlags) { + int nCompressedSize; + + if (apultra_build_suffix_array(pCompressor, pInWindow, nPreviousBlockSize + nInDataSize)) + nCompressedSize = -1; + else { + if (nPreviousBlockSize) { + apultra_skip_matches(pCompressor, 0, nPreviousBlockSize); + } + apultra_find_all_matches(pCompressor, NMATCHES_PER_INDEX, nPreviousBlockSize, nPreviousBlockSize + nInDataSize, nBlockFlags); + + nCompressedSize = apultra_optimize_and_write_block(pCompressor, pInWindow, nPreviousBlockSize, nInDataSize, pOutData, nMaxOutDataSize, nCurBitsOffset, nCurBitShift, nCurFollowsLiteral, nCurRepMatchOffset, nBlockFlags); + } + + return nCompressedSize; +} + +/** + * Get maximum compressed size of input(source) data + * + * @param nInputSize input(source) size in bytes + * + * @return maximum compressed size + */ +size_t apultra_get_max_compressed_size(size_t nInputSize) { + return ((nInputSize * 9 /* literals + literal bits */ + 1 /* match bit */ + 2 /* 7+1 command bits */ + 8 /* EOD offset bits */) + 7) >> 3; +} + +/** + * Compress memory + * + * @param pInputData pointer to input(source) data to compress + * @param pOutBuffer buffer for compressed data + * @param nInputSize input(source) size in bytes + * @param nMaxOutBufferSize maximum capacity of compression buffer + * @param nFlags compression flags (set to 0) + * @param nMaxWindowSize maximum window size to use (0 for default) + * @param nDictionarySize size of dictionary in front of input data (0 for none) + * @param progress progress function, called after compressing each block, or NULL for none + * @param pStats pointer to compression stats that are filled if this function is successful, or NULL + * + * @return actual compressed size, or -1 for error + */ +size_t apultra_compress(const unsigned char *pInputData, unsigned char *pOutBuffer, size_t nInputSize, size_t nMaxOutBufferSize, + const unsigned int nFlags, size_t nMaxWindowSize, size_t nDictionarySize, void(*progress)(long long nOriginalSize, long long nCompressedSize), apultra_stats *pStats) { + apultra_compressor compressor; + size_t nOriginalSize = 0; + size_t nCompressedSize = 0L; + int nResult; + int nMaxArrivals = NARRIVALS_PER_POSITION_SMALL; + int nError = 0; + const int nBlockSize = (nInputSize < BLOCK_SIZE) ? ((nInputSize < 1024) ? 1024 : (int)nInputSize) : BLOCK_SIZE; + const int nMaxOutBlockSize = (int)apultra_get_max_compressed_size(nBlockSize); + + if (nDictionarySize < nInputSize) { + int nInDataSize = (int)(nInputSize - nDictionarySize); + if (nInDataSize > nBlockSize) + nInDataSize = nBlockSize; + + if (nInDataSize > 0 && (nDictionarySize + nInDataSize) >= nInputSize) + nMaxArrivals = NARRIVALS_PER_POSITION; + } + + nResult = apultra_compressor_init(&compressor, nBlockSize, nBlockSize * 2, nMaxArrivals, nFlags); + if (nResult != 0) { + return -1; + } + + compressor.max_offset = nMaxWindowSize ? (int)nMaxWindowSize : MAX_OFFSET; + + int nPreviousBlockSize = 0; + int nNumBlocks = 0; + int nCurBitsOffset = INT_MIN, nCurBitShift = 0, nCurFollowsLiteral = 0; + int nBlockFlags = 1; + int nCurRepMatchOffset = 0; + + if (nDictionarySize) { + nOriginalSize = (int)nDictionarySize; + nPreviousBlockSize = (int)nDictionarySize; + } + + while (nOriginalSize < nInputSize && !nError) { + int nInDataSize; + + nInDataSize = (int)(nInputSize - nOriginalSize); + if (nInDataSize > nBlockSize) + nInDataSize = nBlockSize; + + if (nInDataSize > 0) { + int nOutDataSize; + int nOutDataEnd = (int)(nMaxOutBufferSize - nCompressedSize); + + if (nOutDataEnd > nMaxOutBlockSize) + nOutDataEnd = nMaxOutBlockSize; + + if ((nOriginalSize + nInDataSize) >= nInputSize) + nBlockFlags |= 2; + nOutDataSize = apultra_compressor_shrink_block(&compressor, pInputData + nOriginalSize - nPreviousBlockSize, nPreviousBlockSize, nInDataSize, pOutBuffer + nCompressedSize, nOutDataEnd, + &nCurBitsOffset, &nCurBitShift, &nCurFollowsLiteral, &nCurRepMatchOffset, nBlockFlags); + nBlockFlags &= (~1); + + if (nOutDataSize >= 0) { + /* Write compressed block */ + + if (!nError) { + nOriginalSize += nInDataSize; + nCompressedSize += nOutDataSize; + if (nCurBitsOffset != INT_MIN) + nCurBitsOffset -= nOutDataSize; + } + } + else { + nError = -1; + } + + nPreviousBlockSize = nInDataSize; + nNumBlocks++; + } + + if (!nError && nOriginalSize < nInputSize) { + if (progress) + progress(nOriginalSize, nCompressedSize); + } + } + + if (progress) + progress(nOriginalSize, nCompressedSize); + if (pStats) + *pStats = compressor.stats; + + apultra_compressor_destroy(&compressor); + + if (nError) { + return -1; + } + else { + return nCompressedSize; + } +} diff --git a/tools/rasm/apultra-master/src/shrink.h b/tools/rasm/apultra-master/src/shrink.h new file mode 100644 index 0000000..b721ba9 --- /dev/null +++ b/tools/rasm/apultra-master/src/shrink.h @@ -0,0 +1,172 @@ +/* + * shrink.h - compressor definitions + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by cap by Sven-Åke Dahl. https://github.com/svendahl/cap + * Also inspired by Charles Bloom's compression blog. http://cbloomrants.blogspot.com/ + * With ideas from LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help and support from spke + * + */ + +#ifndef _SHRINK_H +#define _SHRINK_H + +#include "divsufsort.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define LCP_BITS 15 +#define TAG_BITS 4 +#define LCP_MAX ((1U<<(LCP_BITS - TAG_BITS)) - 1) +#define LCP_AND_TAG_MAX ((1U< = run of literals, or + ; 1 + + [7-bits of offset lsb + 1-bit of length] + = another match +@AfterMatch1: + add a, a + jr nc, @RunOfLiterals + +@UsualMatch: ; this is the case of usual match+offset + add a, a + jr nc, @LongerOffets + jr nz, @ShorterOffsets ; NZ after NC == "confirmed C" + + ld a, (hl) ; reload bits + inc hl + rla + + jr c, @ShorterOffsets + +@LongerOffets: + ld c, $fe + + add a, a ; inline read gamma + rl c + add a, a + jr nc, $-4 + + call z, @ReloadReadGamma + +@ProcessOffset: + + inc c + ret z ; end-of-data marker (only checked for longer offsets) + rr c + ld b, c + ld c, (hl) + inc hl + rr c + ld (@PrevOffset+1), bc + + ; lowest bit is the first bit of the gamma code for length + jr c, @CopyMatch2 + +@LongerMatch: + ld bc, 1 + + add a, a ; inline read gamma + rl c + add a, a + jr nc, $-4 + + call z,@ReloadReadGamma + +@CopyMatch3: + push hl ; preserve source + ld hl, (@PrevOffset+1) ; restore offset + add hl, de ; HL = dest - offset + + ; because BC>=3-1, we can do 2 x LDI safely + ldi + ldir + inc c + ldi + pop hl ; restore source + + ; after a match you can have either + ; 0 + = run of literals, or + ; 1 + + [7-bits of offset lsb + 1-bit of length] + = another match +@AfterMatch3: + add a, a + jr c, @UsualMatch + +@RunOfLiterals: + inc c + add a, a + jr nc, @LongerRun + jr nz, @CopyLiteral ; NZ after NC == "confirmed C" + + ld a, (hl) ; reload bits + inc hl + rla + + jr c, @CopyLiteral + +@LongerRun: + add a, a ; inline read gamma + rl c + add a, a + jr nc, $-4 + + jr nz, @CopyLiterals + + ld a, (hl) ; reload bits + inc hl + rla + + call nc, @ReadGammaAligned + +@CopyLiterals: + ldi + +@CopyLiteral: + ldir + + ; after a literal run you can have either + ; 0 + = match using a repeated offset, or + ; 1 + + [7-bits of offset lsb + 1-bit of length] + = another match + add a, a + jr c, @UsualMatch + +@RepMatch: + inc c + add a, a + jr nc, @LongerRepMatch + jr nz, @CopyMatch1 ; NZ after NC == "confirmed C" + + ld a, (hl) ; reload bits + inc hl + rla + + jr c, @CopyMatch1 + +@LongerRepMatch: + add a, a ; inline read gamma + rl c + add a, a + jr nc, $-4 + + jp nz, @CopyMatch1 + + ; this is a crafty equivalent of CALL ReloadReadGamma : JP CopyMatch1 + push ix + + ; the subroutine for reading the remainder of the partly read Elias gamma code. + ; it has two entry points: ReloadReadGamma first refills the bit reservoir in A, + ; while ReadGammaAligned assumes that the bit reservoir has just been refilled. +@ReloadReadGamma: + ld a, (hl) ; reload bits + inc hl + rla + + ret c +@ReadGammaAligned: + add a, a + rl c + add a, a + ret c + add a, a + rl c + add a, a +@ReadingLongGamma: ; this loop does not need unrolling, as it does not get much use anyway + ret c + add a, a + rl c + rl b + add a, a + jr nz, @ReadingLongGamma + + ld a, (hl) ; reload bits + inc hl + rla + jr @ReadingLongGamma +mend + diff --git a/tools/rasm/decrunch/dzx0_standard.asm b/tools/rasm/decrunch/dzx0_standard.asm new file mode 100644 index 0000000..6525c8b --- /dev/null +++ b/tools/rasm/decrunch/dzx0_standard.asm @@ -0,0 +1,64 @@ +; ----------------------------------------------------------------------------- +; ZX0 decoder by Einar Saukas & Urusergi +; "Standard" version (68 bytes only) +; ----------------------------------------------------------------------------- +; Parameters: +; HL: source address (compressed data) +; DE: destination address (decompressing) +; ----------------------------------------------------------------------------- + +macro dzx0_standard + ld bc, $ffff ; preserve default offset 1 + push bc + inc bc + ld a, $80 +@dzx0s_literals: + call @dzx0s_elias ; obtain length + ldir ; copy literals + add a, a ; copy from last offset or new offset? + jr c, @dzx0s_new_offset + call @dzx0s_elias ; obtain length +@dzx0s_copy: + ex (sp), hl ; preserve source, restore offset + push hl ; preserve offset + add hl, de ; calculate destination - offset + ldir ; copy from offset + pop hl ; restore offset + ex (sp), hl ; preserve offset, restore source + add a, a ; copy from literals or new offset? + jr nc, @dzx0s_literals +@dzx0s_new_offset: + pop bc ; discard last offset + ld c, $fe ; prepare negative offset + call @dzx0s_elias_loop ; obtain offset MSB + inc c + ret z ; check end marker + ld b, c + ld c, (hl) ; obtain offset LSB + inc hl + rr b ; last offset bit becomes first length bit + rr c + push bc ; preserve new offset + ld bc, 1 ; obtain length + call nc, @dzx0s_elias_backtrack + inc bc + jr @dzx0s_copy +@dzx0s_elias: + inc c ; interlaced Elias gamma coding +@dzx0s_elias_loop: + add a, a + jr nz, @dzx0s_elias_skip + ld a, (hl) ; load another group of 8 bits + inc hl + rla +@dzx0s_elias_skip: + ret c +@dzx0s_elias_backtrack: + add a, a + rl c + rl b + jr @dzx0s_elias_loop +mend +; ----------------------------------------------------------------------------- + + diff --git a/tools/rasm/decrunch/dzx0_standard_back.asm b/tools/rasm/decrunch/dzx0_standard_back.asm new file mode 100644 index 0000000..3da94bd --- /dev/null +++ b/tools/rasm/decrunch/dzx0_standard_back.asm @@ -0,0 +1,65 @@ +; ----------------------------------------------------------------------------- +; ZX0 decoder by Einar Saukas +; "Standard" version (69 bytes only) - BACKWARDS VARIANT +; ----------------------------------------------------------------------------- +; Parameters: +; HL: last source address (compressed data) +; DE: last destination address (decompressing) +; ----------------------------------------------------------------------------- + +Macro dzx0_standard_back + ld bc, 1 ; preserve default offset 1 + push bc + ld a, $80 +@dzx0sb_literals: + call @dzx0sb_elias ; obtain length + lddr ; copy literals + inc c + add a, a ; copy from last offset or new offset? + jr c, @dzx0sb_new_offset + call @dzx0sb_elias ; obtain length +@dzx0sb_copy: + ex (sp), hl ; preserve source, restore offset + push hl ; preserve offset + add hl, de ; calculate destination - offset + lddr ; copy from offset + inc c + pop hl ; restore offset + ex (sp), hl ; preserve offset, restore source + add a, a ; copy from literals or new offset? + jr nc, @dzx0sb_literals +@dzx0sb_new_offset: + inc sp ; discard last offset + inc sp + call @dzx0sb_elias ; obtain offset MSB + dec b + ret z ; check end marker + dec c ; adjust for positive offset + ld b, c + ld c, (hl) ; obtain offset LSB + dec hl + srl b ; last offset bit becomes first length bit + rr c + inc bc + push bc ; preserve new offset + ld bc, 1 ; obtain length + call c, @dzx0sb_elias_backtrack + inc bc + jr @dzx0sb_copy +@dzx0sb_elias_backtrack: + add a, a + rl c + rl b +@dzx0sb_elias: + add a, a ; inverted interlaced Elias gamma coding + jr nz, @dzx0sb_elias_skip + ld a, (hl) ; load another group of 8 bits + dec hl + rla +@dzx0sb_elias_skip: + jr c, @dzx0sb_elias_backtrack + ret +mend +; ----------------------------------------------------------------------------- + + diff --git a/tools/rasm/decrunch/dzx0_turbo_back.asm b/tools/rasm/decrunch/dzx0_turbo_back.asm new file mode 100644 index 0000000..d009e92 --- /dev/null +++ b/tools/rasm/decrunch/dzx0_turbo_back.asm @@ -0,0 +1,101 @@ +; ----------------------------------------------------------------------------- +; ZX0 decoder by Einar Saukas & introspec +; "Turbo" version (126 bytes, 21% faster) - BACKWARDS VARIANT +; ----------------------------------------------------------------------------- +; Parameters: +; HL: last source address (compressed data) +; DE: last destination address (decompressing) +; ----------------------------------------------------------------------------- + +macro dzx0_turbo_back + ld bc, 1 ; preserve default offset 1 + ld (@dzx0tb_last_offset+1), bc + ld a, $80 + jr @dzx0tb_literals +@dzx0tb_new_offset: + add a, a ; obtain offset MSB + call c, @dzx0tb_elias + dec b + ret z ; check end marker + dec c ; adjust for positive offset + ld b, c + ld c, (hl) ; obtain offset LSB + dec hl + srl b ; last offset bit becomes first length bit + rr c + inc bc + ld (@dzx0tb_last_offset+1), bc ; preserve new offset + ld bc, 1 ; obtain length + call c, @dzx0tb_elias_loop + inc bc +@dzx0tb_copy: + push hl ; preserve source +@dzx0tb_last_offset: + ld hl, 0 ; restore offset + add hl, de ; calculate destination - offset + lddr ; copy from offset + inc c + pop hl ; restore source + add a, a ; copy from literals or new offset? + jr c, @dzx0tb_new_offset +@dzx0tb_literals: + add a, a ; obtain length + call c, @dzx0tb_elias + lddr ; copy literals + inc c + add a, a ; copy from last offset or new offset? + jr c, @dzx0tb_new_offset + add a, a ; obtain length + call c, @dzx0tb_elias + jp @dzx0tb_copy +@dzx0tb_elias_loop: + add a, a + rl c + add a, a + ret nc +@dzx0tb_elias: + jp nz, @dzx0tb_elias_loop ; inverted interlaced Elias gamma coding + ld a, (hl) ; load another group of 8 bits + dec hl + rla + ret nc + add a, a + rl c + add a, a + ret nc + add a, a + rl c + add a, a + ret nc + add a, a + rl c + add a, a + ret nc +@dzx0tb_elias_reload: + add a, a + rl c + rl b + add a, a + ld a, (hl) ; load another group of 8 bits + dec hl + rla + ret nc + add a, a + rl c + rl b + add a, a + ret nc + add a, a + rl c + rl b + add a, a + ret nc + add a, a + rl c + rl b + add a, a + jr c, @dzx0tb_elias_reload + ret +; ----------------------------------------------------------------------------- +mend + diff --git a/tools/rasm/decrunch/dzx7_turbo.asm b/tools/rasm/decrunch/dzx7_turbo.asm index 779ced5..cb66be5 100644 --- a/tools/rasm/decrunch/dzx7_turbo.asm +++ b/tools/rasm/decrunch/dzx7_turbo.asm @@ -8,7 +8,7 @@ ; ----------------------------------------------------------------------------- dzx7_turbo: - ld a, $80 + ld a, #80 dzx7t_copy_byte_loop: ldi ; copy literal byte dzx7t_main_loop: @@ -42,7 +42,7 @@ dzx7t_len_value_start: ; determine offset ld e, (hl) ; load offset flag (1 bit) + offset value (7 bits) inc hl - defb $cb, $33 ; opcode for undocumented instruction "SLL E" aka "SLS E" + defb #cb, #33 ; opcode for undocumented instruction "SLL E" aka "SLS E" jr nc, dzx7t_offset_end ; if offset flag is set, load 4 extra bits add a, a ; check next bit call z, dzx7t_load_bits ; no more bits left? diff --git a/tools/rasm/decrunch/exomizer3megachur.asm b/tools/rasm/decrunch/exomizer3megachur.asm deleted file mode 100644 index ea1973e..0000000 --- a/tools/rasm/decrunch/exomizer3megachur.asm +++ /dev/null @@ -1,210 +0,0 @@ -;Exomizer 2 Z80 decoder -;Copyright (C) 2008-2016 by Jaime Tejedor Gomez (Metalbrain) -; -;Optimized by Antonio Villena and Urusergi (169 bytes) -; -;Compression algorithm by Magnus Lind -; -; This depacker is free software; you can redistribute it and/or -; modify it under the terms of the GNU Lesser General Public -; License as published by the Free Software Foundation; either -; version 2.1 of the License, or (at your option) any later version. -; -; This library is distributed in the hope that it will be useful, -; but WITHOUT ANY WARRANTY; without even the implied warranty of -; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -; Lesser General Public License for more details. -; -; You should have received a copy of the GNU Lesser General Public -; License along with this library; if not, write to the Free Software -; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -; -; -;input- hl=compressed data start -; de=uncompressed destination start -; -; you may change exo_mapbasebits to point to any free buffer -; -;ATTENTION! -;A huge speed boost (around 14%) can be gained at the cost of only 5 bytes. -;If you want this, replace all instances of "call exo_getbit" with "srl a" followed by -;"call z,exo_getbit", and remove the first two instructions in exo_getbit routine. -; --------------------------- -; modified by Megachur in 2018 -; --------------------------- -; hl -> compressed data start -; de -> uncompressed destination start -; --------------------------- - -;EXO_BACKWARD equ 1 -ENABLE_MEXO_GETBIT equ 1 - -list:EXOMIZER_ADDRESS:nolist -; --------------------------- -MACRO MEXO_GETBIT - srl a - jr nz,@1 - ld a,(hl) - IFDEF EXO_BACKWARD - dec hl - ELSE - inc hl - ENDIF - rra -@1 -ENDM - -deexo: - ld iy,exo_mapbasebits+11 - ld a,(hl) - - IFDEF EXO_BACKWARD - dec hl - ELSE - inc hl - ENDIF - - ld b,52 - push de - cp a - -exo_initbits: - ld c,16 - jr nz,exo_get4bits - ld ixl,c - ld de,1 ;DE=b2 - -exo_get4bits: - IFDEF ENABLE_MEXO_GETBIT - MEXO_GETBIT - ELSE - srl a:call z,exo_getbit ;call exo_getbit ;get one bit - ENDIF - rl c - jr nc,exo_get4bits - inc c - push hl - ld hl,1 - ld (iy+41),c ;bits[i]=b1 (and opcode 41 == add hl,hl) - -exo_setbit: - dec c - jr nz,exo_setbit-1 ;jump to add hl,hl instruction - ld (iy-11),e - ld (iy+93),d ;base[i]=b2 - add hl,de - ex de,hl - inc iy - pop hl - dec ixl - djnz exo_initbits - pop de - jr exo_mainloop - -exo_literalrun: - ld e,c ;DE=1 - -exo_getbits: - dec b - ret z - -exo_getbits1: - IFDEF ENABLE_MEXO_GETBIT - MEXO_GETBIT - ELSE - srl a:call z,exo_getbit ;call exo_getbit - ENDIF - rl e - rl d - jr nc,exo_getbits - ld b,d - ld c,e - pop de - -exo_literalcopy: - IFDEF EXO_BACKWARD - lddr - ELSE - ldir - ENDIF -exo_mainloop: - inc c - IFDEF ENABLE_MEXO_GETBIT - MEXO_GETBIT - ELSE - srl a:call z,exo_getbit ;call exo_getbit ;literal? - ENDIF - jr c,exo_literalcopy - ld c,239 -exo_getindex: - IFDEF ENABLE_MEXO_GETBIT - MEXO_GETBIT - ELSE - srl a:call z,exo_getbit ;call exo_getbit - ENDIF - inc c - jr nc,exo_getindex - ret z - push de - ld d,b - jp p,exo_literalrun - ld iy,exo_mapbasebits-229 - call exo_getpair - push de - rlc d - jr nz,exo_dontgo - dec e - ld bc,512+32 ;2 bits,48 offset - jr z,exo_goforit - dec e ;2? -exo_dontgo: - ld bc,1024+16 ;4 bits,32 offset - jr z,exo_goforit - ld de,0 - ld c,d ;16 offset -exo_goforit: - call exo_getbits1 - ld iy,exo_mapbasebits+27 - add iy,de - call exo_getpair - pop bc - ex (sp),hl - IFDEF EXO_BACKWARD - ex de,hl - add hl,de - lddr - ELSE - push hl - sbc hl,de - pop de - ldir - ENDIF - pop hl - jr exo_mainloop ;Next! -exo_getpair: - add iy,bc - ld e,d - ld b,(iy+41) - call exo_getbits - ex de,hl - ld c,(iy-11) - ld b,(iy+93) - add hl,bc ;Always clear C flag - ex de,hl - ret - - IFDEF ENABLE_MEXO_GETBIT - ELSE -exo_getbit: -; srl a -; ret nz - ld a,(hl) - inc hl - rra - ret - ENDIF - -exo_mapbasebits: - ds 156,#00 ;tables for bits,baseL,baseH -; --------------------------- -list:EXOMIZER_ADDRESS_LENGTH equ $-EXOMIZER_ADDRESS:nolist \ No newline at end of file diff --git a/tools/rasm/decrunch/lz48decrunch_v006.asm b/tools/rasm/decrunch/lz48decrunch_v006.asm deleted file mode 100644 index 750b571..0000000 --- a/tools/rasm/decrunch/lz48decrunch_v006.asm +++ /dev/null @@ -1,113 +0,0 @@ -; -; LZ48 decrunch -; -; hl compressed data adress -; de output adress of data -; - - -org #8000 - -; CALL #8000,source,destination -di - -; parameters -ld h,(ix+3) -ld l,(ix+2) -ld d,(ix+1) -ld e,(ix+0) - -call LZ48_decrunch - -ei -ret - - - - - -LZ48_decrunch -ldi -ld b,0 - -nextsequence -ld a,(hl) -inc hl -ld lx,a -and #F0 -jr z,lzunpack ; no litteral bytes -rrca -rrca -rrca -rrca - -ld c,a -cp 15 ; more bytes for length? -jr nz,copyliteral - -getadditionallength -ld a,(hl) -inc hl -inc a -jr nz,lengthnext -inc b -dec bc -jr getadditionallength -lengthnext -dec a -add a,c -ld c,a -ld a,b -adc a,0 -ld b,a ; bc=length - -copyliteral -ldir - -lzunpack -ld a,lx -and #F -add 3 -ld c,a -cp 18 ; more bytes for length? -jr nz,readoffset - -getadditionallengthbis -ld a,(hl) -inc hl -inc a -jr nz,lengthnextbis -inc b -dec bc -jr getadditionallengthbis -lengthnextbis -dec a -add a,c -ld c,a -ld a,b -adc a,0 -ld b,a ; bc=length - -readoffset -; read encoded offset -ld a,(hl) -inc a -ret z ; LZ48 end with zero offset -inc hl -push hl -ld l,a -ld a,e -sub l -ld l,a -ld a,d -sbc a,0 -ld h,a -; source=dest-copyoffset - -copykey -ldir - -pop hl -jr nextsequence - - diff --git a/tools/rasm/decrunch/lz48decrunch_v006b.asm b/tools/rasm/decrunch/lz48decrunch_v006b.asm new file mode 100644 index 0000000..69162a4 --- /dev/null +++ b/tools/rasm/decrunch/lz48decrunch_v006b.asm @@ -0,0 +1,78 @@ +; +; LZ48 decrunch +; + +; In ; HL=compressed data address +; ; DE=output data address +; Out ; HL last address of compressed data read (you must inc once for LZ48 stream) +; ; DE last address of decrunched data write +1 +; ; BC always 3 +; ; A always zero +; ; IXL undetermined +; ; flags (inc a -> 0) +; Modif ; AF, BC, DE, HL, IXL +LZ48_decrunch + ldi + ld b,0 + +nextsequence + ld a,(hl) + inc hl + cp #10 + jr c,lzunpack ; no literal bytes + ld ixl,a + and #f0 + rrca + rrca + rrca + rrca + + cp 15 ; more bytes for literal length? + jr nz,copyliteral +getadditionallength + ld c,(hl) ; get additional literal length byte + inc hl + add a,c ; compute literal length total + jr nc,lengthNC + inc b +lengthNC + inc c + jr z,getadditionallength ; if last literal length byte was 255, we have more bytes to process +copyliteral + ld c,a + ldir + ld a,ixl + and #F +lzunpack + add 3 + cp 18 ; more bytes for match length? + jr nz,readoffset +getadditionallengthbis + ld c,(hl) ; get additional match length byte + inc hl + add a,c ; compute match length size total + jr nc,lengthNCbis + inc b +lengthNCbis + inc c + jr z,getadditionallengthbis ; if last match length byte was 255, we have more bytes to process + +readoffset + ld c,a +; read encoded offset + ld a,(hl) + inc a + ret z ; LZ48 end with zero offset + inc hl + push hl +; source=dest-copyoffset + ; A != 0 here + neg + ld l,a + ld h,#ff + add hl,de +copykey + ldir + + pop hl + jr nextsequence diff --git a/tools/rasm/decrunch/unaplib.asm b/tools/rasm/decrunch/unaplib.asm new file mode 100644 index 0000000..13c8678 --- /dev/null +++ b/tools/rasm/decrunch/unaplib.asm @@ -0,0 +1,190 @@ +;Z80 Version by Dan Weiss +;Call depack. +;hl = source +;de = dest + +ap_bits: db 0 +ap_byte: db 0 +lwm: db 0 +r0: dw 0 + +ap_getbit: + push bc + ld bc,(ap_bits) + rrc c + jr nc,ap_getbit_continue + ld b,(hl) + inc hl +ap_getbit_continue: + ld a,c + and b + ld (ap_bits),bc + pop bc + ret + +ap_getbitbc: ;doubles BC and adds the read bit + sla c + rl b + call ap_getbit + ret z + inc bc + ret + +ap_getgamma: + ld bc,1 +ap_getgammaloop: + call ap_getbitbc + call ap_getbit + jr nz,ap_getgammaloop + ret + + +depack: + ;hl = source + ;de = dest + ldi + xor a + ld (lwm),a + inc a + ld (ap_bits),a + +aploop: + call ap_getbit + jp z, apbranch1 + call ap_getbit + jr z, apbranch2 + call ap_getbit + jr z, apbranch3 + ;LWM = 0 + xor a + ld (lwm),a + ;get an offset + ld bc,0 + call ap_getbitbc + call ap_getbitbc + call ap_getbitbc + call ap_getbitbc + ld a,b + or c + jr nz,apbranch4 + xor a ;write a 0 + ld (de),a + inc de + jr aploop +apbranch4: + ex de,hl ;write a previous bit (1-15 away from dest) + push hl + sbc hl,bc + ld a,(hl) + pop hl + ld (hl),a + inc hl + ex de,hl + jr aploop +apbranch3: + ;use 7 bit offset, length = 2 or 3 + ;if a zero is encountered here, it's EOF + ld c,(hl) + inc hl + rr c + ret z + ld b,2 + jr nc,ap_dont_inc_b + inc b +ap_dont_inc_b: + ;LWM = 1 + ld a,1 + ld (lwm),a + + push hl + ld a,b + ld b,0 + ;R0 = c + ld (r0),bc + ld h,d + ld l,e + or a + sbc hl,bc + ld c,a + ldir + pop hl + jr aploop +apbranch2: + ;use a gamma code * 256 for offset, another gamma code for length + call ap_getgamma + dec bc + dec bc + ld a,(lwm) + or a + jr nz,ap_not_lwm + ;bc = 2? + ld a,b + or c + jr nz,ap_not_zero_gamma + ;if gamma code is 2, use old r0 offset, and a new gamma code for length + call ap_getgamma + push hl + ld h,d + ld l,e + push bc + ld bc,(r0) + sbc hl,bc + pop bc + ldir + pop hl + jr ap_finishup + +ap_not_zero_gamma: + dec bc +ap_not_lwm: + ;do I even need this code? + ;bc=bc*256+(hl), lazy 16bit way + ld b,c + ld c,(hl) + inc hl + ld (r0),bc + push bc + call ap_getgamma + ex (sp),hl + ;bc = len, hl=offs + push de + ex de,hl + ;some comparison junk for some reason + ld hl,31999 + or a + sbc hl,de + jr nc,skip1 + inc bc +skip1: + ld hl,1279 + or a + sbc hl,de + jr nc,skip2 + inc bc +skip2: + ld hl,127 + or a + sbc hl,de + jr c,skip3 + inc bc + inc bc +skip3: + ;bc = len, de = offs, hl=junk + pop hl + push hl + or a + sbc hl,de + pop de + ;hl=dest-offs, bc=len, de = dest + ldir + pop hl +ap_finishup: + ld a,1 + ld (lwm),a + jp aploop + +apbranch1: + ldi + xor a + ld (lwm),a + jp aploop diff --git a/tools/rasm/decrunch/unaplib_fast.asm b/tools/rasm/decrunch/unaplib_fast.asm new file mode 100644 index 0000000..47ad16b --- /dev/null +++ b/tools/rasm/decrunch/unaplib_fast.asm @@ -0,0 +1,266 @@ +; +; Speed-optimized ApLib decompressor by spke (ver.04 spring 2020, 236 bytes) +; +; The original Z80 decompressors for ApLib were written by Dan Weiss (Dwedit), +; then tweaked by Francisco Javier Pena Pareja (utopian), +; and optimized by Jaime Tejedor Gomez (Metalbrain) and Antonio Villena. +; +; This is a new "implicit state" decompressor heavily optimized for speed by spke. +; (It is 11 bytes shorter and 14% faster than the previously fastest +; 247b decompressor by Metalbrain and Antonio Villena.) +; +; ver.00 by spke (21/08/2018-01/09/2018, 244 bytes, an edit of the existing 247b decompressor); +; ver.01 by spke (12-13/11/2018, 234(-10) bytes, +3% speed using the state machine for LWM); +; ver.02 by spke (06/08/2019, +1% speed); +; ver.03 by spke (27/08/2019, 236(+2) bytes, +1% speed using partly expanded LDIR); +; ver.04 by spke (spring 2020, added full revision history and support for long offsets) +; +; The data must be compressed using any compressor for ApLib capable of generating raw data. +; At present, two best available compressors are: +; +; "APC" by Sven-Ake Dahl: https://github.com/svendahl/cap or +; "apultra" by Emmanuel Marty: https://github.com/emmanuel-marty/apultra +; +; The compression can done as follows: +; +; apc.exe e +; or +; apultra.exe +; +; A decent compressor was written by r57shell (although it is worse than compressors above): +; http://gendev.spritesmind.net/forum/viewtopic.php?p=32548#p32548 +; The use of the official ApLib compressor by Joergen Ibsen is not recommended. +; +; The decompression is done in the standard way: +; +; ld hl,FirstByteOfCompressedData +; ld de,FirstByteOfMemoryForDecompressedData +; call DecompressApLib +; +; The decompressor modifies AF, AF', BC, DE, HL, IXH, IY. +; (However, note that the option "AllowSelfmodifyingCode" removes the dependency on IY.) +; +; Of course, ApLib compression algorithms are (c) 1998-2014 Joergen Ibsen, +; see http://www.ibsensoftware.com/ for more information +; +; Drop me an email if you have any comments/ideas/suggestions: zxintrospec@gmail.com +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any damages +; arising from the use of this software. +; +; Permission is granted to anyone to use this software for any purpose, +; including commercial applications, and to alter it and redistribute it +; freely, subject to the following restrictions: +; +; 1. The origin of this software must not be misrepresented; you must not +; claim that you wrote the original software. If you use this software +; in a product, an acknowledgment in the product documentation would be +; appreciated but is not required. +; 2. Altered source versions must be plainly marked as such, and must not be +; misrepresented as being the original software. +; 3. This notice may not be removed or altered from any source distribution. + +; DEFINE SupportLongOffsets ; +4 bytes for long offset support. slows decompression down by 1%, but may be needed to decompress files >=32K + +MACRO ApUnpack + + ld a,128 : jr @LWM0_CASE0 + +;================================================================================================================== +;================================================================================================================== +;================================================================================================================== + +@LWM0: ;LWM = 0 (LWM stands for "Last Was Match"; a flag that we did not have a match) + +@LWM0_ReloadByteC0 ld a,(hl) : inc hl : rla + jr c,@LWM0_Check2ndBit + +; +; case "0"+BYTE: copy a single literal + +@LWM0_CASE0: ldi ; first byte is always copied as literal + +; +; main decompressor loop + +@LWM0_MainLoop: add a : jr z,@LWM0_ReloadByteC0 : jr nc,@LWM0_CASE0 ; "0"+BYTE = copy literal +@LWM0_Check2ndBit add a : call z,@ReloadByte : jr nc,@LWM0_CASE10 ; "10"+gamma(offset/256)+BYTE+gamma(length) = the main matching mechanism + add a : call z,@ReloadByte : jp c,@LWM1_CASE111 ; "110"+[oooooool] = matched 2-3 bytes with a small offset + +; +; branch "110"+[oooooool]: copy two or three bytes (bit "l") with the offset -1..-127 (bits "ooooooo"), or stop + +@LWM0_CASE110: ; "use 7 bit offset, length = 2 or 3" + ; "if a zero is found here, it's EOF" + ld c,(hl) : rr c : ret z ; process EOF + inc hl + ld b,0 + + ld iyl,c : ld iyh,b ; save offset for future LWMs + + push hl ; save src + ld h,d : ld l,e ; HL = dest + jr c,@LWM0_LengthIs3 + +@LWM0_LengthIs2 sbc hl,bc + ldi : ldi + jr @LWM0_PreMainLoop + +@LWM0_LengthIs3 or a : sbc hl,bc + ldi : ldi : ldi + jr @LWM0_PreMainLoop + +; +; branch "10"+gamma(offset/256)+BYTE+gamma(length): the main matching mechanism + +@LWM0_CASE10: ; "use a gamma code * 256 for offset, another gamma code for length" + call @GetGammaCoded + + ; the original decompressor contains + ; + ; if ((LWM == 0) && (offs == 2)) { ... } + ; else { + ; if (LWM == 0) { offs -= 3; } + ; else { offs -= 2; } + ; } + ; + ; so, the idea here is to use the fact that GetGammaCoded returns (offset/256)+2, + ; and to split the first condition by noticing that C-1 can never be zero + dec c : dec c : jr z,@LWM1_KickInLWM + +@LWM0_AfterLWM dec c : ld b,c : ld c,(hl) : inc hl ; BC = offset + + ld iyl,c : ld iyh,b : push bc + + call @GetGammaCoded ; BC = len* + + ex (sp),hl + + ; interpretation of length value is offset-dependent: + ; if (offs >= 32000) len++; if (offs >= 1280) len++; if (offs < 128) len+=2; + ; in other words, + ; (1 <= offs < 128) +=2 + ; (128 <= offs < 1280) +=0 + ; (1280 <= offs < 31999) +=1 + ; NB offsets over 32000 need one more check, but other Z80 decompressors seem to ignore it. is it not needed? + + ; interpretation of length value is offset-dependent + exa : ld a,h + IFDEF SupportLongOffsets + ; NB offsets over 32000 require an additional check, which is skipped in most + ; Z80 decompressors (seemingly as a performance optimization) + cp 32000>>8 : jr nc,@LWM0_Add2 + ENDIF + cp 5 : jr nc,@LWM0_Add1 + or a : jr nz,@LWM0_Add0 + bit 7,l : jr nz,@LWM0_Add0 +@LWM0_Add2 inc bc +@LWM0_Add1 inc bc +@LWM0_Add0 ; for offs<128 : 4+4+7+7 + 4+7 + 8+7 + 6+6 = 60t + ; for offs>=1280 : 4+4+7+12 + 6 = 33t + ; for 128<=offs<1280 : 4+4+7+7 + 4+12 = 38t OR 4+4+7+7 + 4+7+8+12 = 53t +; dec bc + +@LWM0_CopyMatch: ; this assumes that BC = len, DE = offset, HL = dest + ; and also that (SP) = src, while having NC + ld a,e : sub l : ld l,a + ld a,d : sbc h +@LWM0_CopyMatchLDH ld h,a : ldi : ldir : exa +@LWM0_PreMainLoop pop hl ; recover src + +;================================================================================================================== +;================================================================================================================== +;================================================================================================================== + +@LWM1: ; LWM = 1 + +; +; main decompressor loop + +@LWM1_MainLoop: add a : jr z,@LWM1_ReloadByteC0 : jr nc,@LWM0_CASE0 ; "0"+BYTE = copy literal +@LWM1_Check2ndBit add a : call z,@ReloadByte : jr nc,@LWM1_CASE10 ; "10"+gamma(offset/256)+BYTE+gamma(length) = the main matching mechanism + add a : call z,@ReloadByte : jr nc,@LWM0_CASE110 ; "110"+[oooooool] = matched 2-3 bytes with a small offset + +; +; case "111"+"oooo": copy a byte with offset -1..-15, or write zero to dest + +@LWM1_CASE111: ld bc,%11100000 + add a : call z,@ReloadByte : rl c ; read short offset (4 bits) + add a : call z,@ReloadByte : rl c ; read short offset (4 bits) + add a : call z,@ReloadByte : rl c ; read short offset (4 bits) + add a : call z,@ReloadByte : rl c ; read short offset (4 bits) + ex de,hl : jr z,@LWM1_WriteZero ; zero offset means "write zero" (NB: B is zero here) + + ; "write a previous byte (1-15 away from dest)" + push hl ; BC = offset, DE = src, HL = dest + sbc hl,bc ; HL = dest-offset (SBC works because branching above ensured NC) + ld b,(hl) + pop hl + +@LWM1_WriteZero ld (hl),b : ex de,hl + inc de : jp @LWM0_MainLoop ; 10+4*(4+10+8)+4+7 + 11+15+7+10 + 7+4+6+10 = 179t + +@LWM1_ReloadByteC0 ld a,(hl) : inc hl : rla + jp nc,@LWM0_CASE0 + jr @LWM1_Check2ndBit + +; +; branch "10"+gamma(offset/256)+BYTE+gamma(length): the main matching mechanism + +@LWM1_CASE10: ; "use a gamma code * 256 for offset, another gamma code for length" + call @GetGammaCoded + + ; the original decompressor contains + ; + ; if ((LWM == 0) && (offs == 2)) { ... } + ; else { + ; if (LWM == 0) { offs -= 3; } + ; else { offs -= 2; } + ; } + ; + ; so, the idea here is to use the fact that GetGammaCoded returns (offset/256)+2, + ; and to split the first condition by noticing that C-1 can never be zero + dec c : jp @LWM0_AfterLWM + +; +; the re-use of the previous offset (LWM magic) + +@LWM1_KickInLWM: ; "and a new gamma code for length" + call @GetGammaCoded ; BC = len + push hl + exa : ld a,e : sub iyl : ld l,a + ld a,d : sbc iyh + jp @LWM0_CopyMatchLDH + +;================================================================================================================== +;================================================================================================================== +;================================================================================================================== + +; +; interlaced gamma code reader +; x0 -> 1x +; x1y0 -> 1xy +; x1y1z0 -> 1xyz etc +; (technically, this is a 2-based variation of Exp-Golomb-1) + +@GetGammaCoded: ld bc,1 +@ReadGamma add a : jr z,@ReloadByteRG1 + rl c : rl b + add a : jr z,@ReloadByteRG2 + jr c,@ReadGamma : ret + +@ReloadByteRG1 ld a,(hl) : inc hl : rla + rl c : rl b + add a : jr c,@ReadGamma : ret + +@ReloadByteRG2 ld a,(hl) : inc hl : rla + jr c,@ReadGamma : ret + +; +; pretty usual getbit for mixed datastreams + +@ReloadByte: ld a,(hl) : inc hl : rla : ret + +MEND + diff --git a/tools/rasm/decrunch/unlzsa1_fast.asm b/tools/rasm/decrunch/unlzsa1_fast.asm new file mode 100644 index 0000000..0e2617f --- /dev/null +++ b/tools/rasm/decrunch/unlzsa1_fast.asm @@ -0,0 +1,204 @@ +; +; Speed-optimized LZSA1 decompressor by spke & uniabis (109 bytes) +; +; ver.00 by spke for LZSA 0.5.4 (03-24/04/2019, 134 bytes); +; ver.01 by spke for LZSA 0.5.6 (25/04/2019, 110(-24) bytes, +0.2% speed); +; ver.02 by spke for LZSA 1.0.5 (24/07/2019, added support for backward decompression); +; ver.03 by uniabis (30/07/2019, 109(-1) bytes, +3.5% speed); +; ver.04 by spke (31/07/2019, small re-organization of macros); +; ver.05 by uniabis (22/08/2019, 107(-2) bytes, same speed); +; ver.06 by spke for LZSA 1.0.7 (27/08/2019, 111(+4) bytes, +2.1% speed); +; ver.07 by spke for LZSA 1.1.0 (25/09/2019, added full revision history); +; ver.08 by spke for LZSA 1.1.2 (22/10/2019, re-organized macros and added an option for unrolled copying of long matches); +; ver.09 by spke for LZSA 1.2.1 (02/01/2020, 109(-2) bytes, same speed) +; +; The data must be compressed using the command line compressor by Emmanuel Marty +; The compression is done as follows: +; +; lzsa.exe -f1 -r +; +; where option -r asks for the generation of raw (frame-less) data. +; +; The decompression is done in the standard way: +; +; ld hl,FirstByteOfCompressedData +; ld de,FirstByteOfMemoryForDecompressedData +; call DecompressLZSA1 +; +; Backward compression is also supported; you can compress files backward using: +; +; lzsa.exe -f1 -r -b +; +; and decompress the resulting files using: +; +; ld hl,LastByteOfCompressedData +; ld de,LastByteOfMemoryForDecompressedData +; call DecompressLZSA1 +; +; (do not forget to uncomment the BACKWARD_DECOMPRESS option in the decompressor). +; +; Of course, LZSA compression algorithms are (c) 2019 Emmanuel Marty, +; see https://github.com/emmanuel-marty/lzsa for more information +; +; Drop me an email if you have any comments/ideas/suggestions: zxintrospec@gmail.com +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any damages +; arising from the use of this software. +; +; Permission is granted to anyone to use this software for any purpose, +; including commercial applications, and to alter it and redistribute it +; freely, subject to the following restrictions: +; +; 1. The origin of this software must not be misrepresented; you must not +; claim that you wrote the original software. If you use this software +; in a product, an acknowledgment in the product documentation would be +; appreciated but is not required. +; 2. Altered source versions must be plainly marked as such, and must not be +; misrepresented as being the original software. +; 3. This notice may not be removed or altered from any source distribution. + +; DEFINE UNROLL_LONG_MATCHES ; uncomment for faster decompression of very compressible data (+57 bytes) +; DEFINE BACKWARD_DECOMPRESS + + IFNDEF BACKWARD_DECOMPRESS + + MACRO NEXT_HL + inc hl + ENDM + + MACRO ADD_OFFSET + ex de,hl : add hl,de + ENDM + + MACRO COPY1 + ldi + ENDM + + MACRO COPYBC + ldir + ENDM + + ELSE + + MACRO NEXT_HL + dec hl + ENDM + + MACRO ADD_OFFSET + ex de,hl : ld a,e : sub l : ld l,a + ld a,d : sbc h : ld h,a ; 4*4+3*4 = 28t / 7 bytes + ENDM + + MACRO COPY1 + ldd + ENDM + + MACRO COPYBC + lddr + ENDM + + ENDIF + +macro DecompressLZSA1 + ld b,0 : jr @ReadToken + +@NoLiterals: xor (hl) : NEXT_HL : jp m,@LongOffset + +@ShortOffset: push de : ld e,(hl) : ld d,#FF + + ; short matches have length 0+3..14+3 + add 3 : cp 15+3 : jr nc,@LongerMatch + + ; placed here this saves a JP per iteration +@CopyMatch: ld c,a +.UseC NEXT_HL : ex (sp),hl ; BC = len, DE = offset, HL = dest, SP ->[dest,src] + ADD_OFFSET ; BC = len, DE = dest, HL = dest-offset, SP->[src] + COPY1 : COPY1 : COPYBC ; BC = 0, DE = dest +.popSrc pop hl ; HL = src + +@ReadToken: ; first a byte token "O|LLL|MMMM" is read from the stream, + ; where LLL is the number of literals and MMMM is + ; a length of the match that follows after the literals + ld a,(hl) : and #70 : jr z,@NoLiterals + + cp #70 : jr z,@MoreLiterals ; LLL=7 means 7+ literals... + rrca : rrca : rrca : rrca : ld c,a ; LLL<7 means 0..6 literals... + + ld a,(hl) : NEXT_HL + COPYBC + + ; the top bit of token is set if the offset contains two bytes + and #8F : jp p,@ShortOffset + +@LongOffset: ; read second byte of the offset + push de : ld e,(hl) : NEXT_HL : ld d,(hl) + add -128+3 : cp 15+3 : jp c,@CopyMatch + + IFNDEF UNROLL_LONG_MATCHES + + ; MMMM=15 indicates a multi-byte number of literals +@LongerMatch: NEXT_HL : add (hl) : jr nc,@CopyMatch + + ; the codes are designed to overflow; + ; the overflow value 1 means read 1 extra byte + ; and overflow value 0 means read 2 extra bytes +.code1 ld b,a : NEXT_HL : ld c,(hl) : jr nz,@CopyMatch.UseC +.code0 NEXT_HL : ld b,(hl) + + ; the two-byte match length equal to zero + ; designates the end-of-data marker + ld a,b : or c : jr nz,@CopyMatch.UseC + pop de : ret + + ELSE + + ; MMMM=15 indicates a multi-byte number of literals +@LongerMatch: NEXT_HL : add (hl) : jr c,@VeryLongMatch + + ld c,a +.UseC NEXT_HL : ex (sp),hl + ADD_OFFSET + COPY1 : COPY1 + + ; this is an unrolled equivalent of LDIR + xor a : sub c + and 32-1 : add a + ld (.jrOffset),a : jr nz,$+2 +.jrOffset EQU $-1 +.fastLDIR repeat 32 + COPY1 + rend + jp pe,.fastLDIR + jp @CopyMatch.popSrc + +@VeryLongMatch: ; the codes are designed to overflow; + ; the overflow value 1 means read 1 extra byte + ; and overflow value 0 means read 2 extra bytes +.code1 ld b,a : NEXT_HL : ld c,(hl) : jr nz,@LongerMatch.UseC +.code0 NEXT_HL : ld b,(hl) + + ; the two-byte match length equal to zero + ; designates the end-of-data marker + ld a,b : or c : jr nz,@LongerMatch.UseC + pop de : ret + + ENDIF + +@MoreLiterals: ; there are three possible situations here + xor (hl) : NEXT_HL : exa + ld a,7 : add (hl) : jr c,@ManyLiterals + +@CopyLiterals: ld c,a +.UseC NEXT_HL : COPYBC + + exa : jp p,@ShortOffset : jr @LongOffset + +@ManyLiterals: +.code1 ld b,a : NEXT_HL : ld c,(hl) : jr nz,@CopyLiterals.UseC +.code0 NEXT_HL : ld b,(hl) : jr @CopyLiterals.UseC + +mend + + + diff --git a/tools/rasm/decrunch/unlzsa2_fast.asm b/tools/rasm/decrunch/unlzsa2_fast.asm new file mode 100755 index 0000000..8c6b5b1 --- /dev/null +++ b/tools/rasm/decrunch/unlzsa2_fast.asm @@ -0,0 +1,189 @@ +; +; Speed-optimized LZSA2 decompressor by spke & uniabis (216 bytes) +; + + DEFINE UNROLL_LONG_MATCHES ; uncomment for faster decompression of very compressible data (+38 bytes) +; DEFINE BACKWARD_DECOMPRESS ; uncomment for data compressed with option -b + + IFNDEF BACKWARD_DECOMPRESS + + MACRO NEXT_HL + inc hl + ENDM + + MACRO ADD_OFFSET + ex de,hl : add hl,de + ENDM + + MACRO COPY1 + ldi + ENDM + + MACRO COPYBC + ldir + ENDM + + ELSE + + MACRO NEXT_HL + dec hl + ENDM + + MACRO ADD_OFFSET + ex de,hl : ld a,e : sub l : ld l,a + ld a,d : sbc h : ld h,a ; 4*4+3*4 = 28t / 7 bytes + ENDM + + MACRO COPY1 + ldd + ENDM + + MACRO COPYBC + lddr + ENDM + + ENDIF + + +macro DecompressLZSA2 +@lzsa2 + ; A' stores next nibble as %1111.... or assumed to contain trash + ; B is assumed to be 0 + ld b,0 : scf : exa : jr .ReadToken + +.ManyLiterals: ld a,18 : add (hl) : NEXT_HL : jr nc,.CopyLiterals + ld c,(hl) : NEXT_HL + ld a,b : ld b,(hl) + jr .NEXTHLuseBC + + +.MoreLiterals: ld b,(hl) : NEXT_HL + scf : exa : jr nc,.noUpdatemoar + + ld a,(hl) : or #F0 : exa + ld a,(hl) : NEXT_HL : or #0F + rrca : rrca : rrca : rrca + +.noUpdatemoar ;sub #F0-3 : cp 15+3 : jr z,ManyLiterals + inc a : jr z,.ManyLiterals : sub #F0-3+1 + +.CopyLiterals: ld c,a : ld a,b : ld b,0 + COPYBC + push de : or a : jp p,.CASE0xx ;: jr CASE1xx + + cp %11000000 : jr c,.CASE10x + +.CASE11x cp %11100000 : jr c,.CASE110 + + ; "111": repeated offset +.CASE111: ld de,ix : jr .MatchLen + + +.Literals0011: jr nz,.MoreLiterals + + ; if "LL" of the byte token is equal to 0, + ; there are no literals to copy +.NoLiterals: or (hl) : NEXT_HL + push de : jp m,.CASE1xx + + ; short (5 or 9 bit long) offsets +.CASE0xx ld d,#FF : cp %01000000 : jr c,.CASE00x + + ; "01x": the case of the 9-bit offset +.CASE01x: cp %01100000 : rl d + +.ReadOffsetE ld e,(hl) : NEXT_HL + +.SaveOffset: LD ix,de + +.MatchLen: inc a : and %00000111 : jr z,.LongerMatch : inc a + +.CopyMatch: ld c,a +;.useC + ex (sp),hl ; BC = len, DE = offset, HL = dest, SP ->[dest,src] + ADD_OFFSET ; BC = len, DE = dest, HL = dest-offset, SP->[src] + COPY1 + COPYBC +.popSrc pop hl + + ; compressed data stream contains records + ; each record begins with the byte token "XYZ|LL|MMM" +.ReadToken: ld a,(hl) : and %00011000 : jp pe,.Literals0011 ; process the cases 00 and 11 separately + + rrca : rrca : rrca + + ld c,a : ld a,(hl) ; token is re-read for further processing +.NEXTHLuseBC NEXT_HL + COPYBC + + ; the token and literals are followed by the offset + push de : or a : jp p,.CASE0xx + +.CASE1xx cp %11000000 : jr nc,.CASE11x + + ; "10x": the case of the 13-bit offset +.CASE10x: ld c,a : exa : jr nc,.noUpdatecase10x + + ld a,(hl) : or #F0 : exa + ld a,(hl) : NEXT_HL : or #0F + rrca : rrca : rrca : rrca + +.noUpdatecase10x ld d,a : ld a,c + cp %10100000 : dec d : rl d : jr .ReadOffsetE + + + + ; "110": 16-bit offset +.CASE110: ld d,(hl) : NEXT_HL : jr .ReadOffsetE + + + + + ; "00x": the case of the 5-bit offset +.CASE00x: ld c,a : exa : jr nc,.noUpdatecase00x + + ld a,(hl) : or #F0 : exa + ld a,(hl) : NEXT_HL : or #0F + rrca : rrca : rrca : rrca + +.noUpdatecase00x ld e,a : ld a,c + cp %00100000 : rl e : jp .SaveOffset + + +.LongerMatch: scf : exa : jr nc,.noUpdatelongermatch + + ld a,(hl) : or #F0 : exa + ld a,(hl) : NEXT_HL : or #0F + rrca : rrca : rrca : rrca + +.noUpdatelongermatch sub #F0-9 : cp 15+9 : jr c,.CopyMatch + + +.LongMatch: add (hl) : NEXT_HL : jr c,.VeryLongMatch + + ld c,a +.useC ex (sp),hl + ADD_OFFSET + COPY1 + + ; this is an unrolled equivalent of LDIR + xor a : sub c + and 32-1 : add a + ld (.jrOffset),a : jr nz,$+2 +.jrOffset EQU $-1 +.fastLDIR repeat 32 + COPY1 + rend + jp pe,.fastLDIR + jp .popSrc + +.VeryLongMatch: ld c,(hl) : NEXT_HL + ld b,(hl) : NEXT_HL : jr nz,.useC + pop de : ret + +mend + + + + + diff --git a/tools/rasm/documentation_EN.pdf b/tools/rasm/documentation_EN.pdf new file mode 100644 index 0000000..2cc0326 Binary files /dev/null and b/tools/rasm/documentation_EN.pdf differ diff --git a/tools/rasm/documentation_FR.pdf b/tools/rasm/documentation_FR.pdf new file mode 100644 index 0000000..04924d9 Binary files /dev/null and b/tools/rasm/documentation_FR.pdf differ diff --git a/tools/rasm/exomizer.h b/tools/rasm/exomizer.h index 1f3c7ca..4f0f7e3 100644 --- a/tools/rasm/exomizer.h +++ b/tools/rasm/exomizer.h @@ -4861,7 +4861,6 @@ unsigned char *Exomizer_crunch(unsigned char *input_data, int input_len, int *re int argc=1; char **argv=NULL; char flags_arr[32]; - int decrunch_mode = 0; int backwards_mode = 0; int reverse_mode = 0; int c, infilec; diff --git a/tools/rasm/lz4.h b/tools/rasm/lz4.h index f34bae4..863fd54 100644 --- a/tools/rasm/lz4.h +++ b/tools/rasm/lz4.h @@ -600,14 +600,14 @@ LZ4LIB_API LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") int LZ4 * Basic Types **************************************/ #if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) - typedef uint8_t BYTE; + typedef uint8_t U8; typedef uint16_t U16; typedef uint32_t U32; typedef int32_t S32; typedef uint64_t U64; typedef uintptr_t uptrval; #else - typedef unsigned char BYTE; + typedef unsigned char U8; typedef unsigned short U16; typedef unsigned int U32; typedef signed int S32; @@ -626,7 +626,7 @@ LZ4LIB_API LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") int LZ4 **************************************/ static unsigned LZ4_isLittleEndian(void) { - const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ + const union { U32 u; U8 c[4]; } one = { 1 }; /* don't use static : performance detrimental */ return one.c[0]; } @@ -689,7 +689,7 @@ static U16 LZ4_readLE16(const void* memPtr) if (LZ4_isLittleEndian()) { return LZ4_read16(memPtr); } else { - const BYTE* p = (const BYTE*)memPtr; + const U8* p = (const U8*)memPtr; return (U16)((U16)p[0] + (p[1]<<8)); } } @@ -699,9 +699,9 @@ static void LZ4_writeLE16(void* memPtr, U16 value) if (LZ4_isLittleEndian()) { LZ4_write16(memPtr, value); } else { - BYTE* p = (BYTE*)memPtr; - p[0] = (BYTE) value; - p[1] = (BYTE)(value>>8); + U8* p = (U8*)memPtr; + p[0] = (U8) value; + p[1] = (U8)(value>>8); } } @@ -713,9 +713,9 @@ static void LZ4_copy8(void* dst, const void* src) /* customized variant of memcpy, which can overwrite up to 8 bytes beyond dstEnd */ static void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd) { - BYTE* d = (BYTE*)dstPtr; - const BYTE* s = (const BYTE*)srcPtr; - BYTE* const e = (BYTE*)dstEnd; + U8* d = (U8*)dstPtr; + const U8* s = (const U8*)srcPtr; + U8* const e = (U8*)dstEnd; do { LZ4_copy8(d,s); d+=8; s+=8; } while (ddictSize; - const BYTE* const dictionary = cctx->dictionary; - const BYTE* const dictEnd = dictionary + cctx->dictSize; - const ptrdiff_t dictDelta = dictEnd - (const BYTE*)source; - const BYTE* anchor = (const BYTE*) source; - const BYTE* const iend = ip + inputSize; - const BYTE* const mflimit = iend - MFLIMIT; - const BYTE* const matchlimit = iend - LASTLITERALS; - - BYTE* op = (BYTE*) dest; - BYTE* const olimit = op + maxOutputSize; + const U8* ip = (const U8*) source; + const U8* base; + const U8* lowLimit; + const U8* const lowRefLimit = ip - cctx->dictSize; + const U8* const dictionary = cctx->dictionary; + const U8* const dictEnd = dictionary + cctx->dictSize; + const ptrdiff_t dictDelta = dictEnd - (const U8*)source; + const U8* anchor = (const U8*) source; + const U8* const iend = ip + inputSize; + const U8* const mflimit = iend - MFLIMIT; + const U8* const matchlimit = iend - LASTLITERALS; + + U8* op = (U8*) dest; + U8* const olimit = op + maxOutputSize; U32 forwardH; @@ -959,16 +959,16 @@ FORCE_INLINE int LZ4_compress_generic( { case noDict: default: - base = (const BYTE*)source; - lowLimit = (const BYTE*)source; + base = (const U8*)source; + lowLimit = (const U8*)source; break; case withPrefix64k: - base = (const BYTE*)source - cctx->currentOffset; - lowLimit = (const BYTE*)source - cctx->dictSize; + base = (const U8*)source - cctx->currentOffset; + lowLimit = (const U8*)source - cctx->dictSize; break; case usingExtDict: - base = (const BYTE*)source - cctx->currentOffset; - lowLimit = (const BYTE*)source; + base = (const U8*)source - cctx->currentOffset; + lowLimit = (const U8*)source; break; } if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */ @@ -981,11 +981,11 @@ FORCE_INLINE int LZ4_compress_generic( /* Main Loop */ for ( ; ; ) { ptrdiff_t refDelta = 0; - const BYTE* match; - BYTE* token; + const U8* match; + U8* token; /* Find a match */ - { const BYTE* forwardIp = ip; + { const U8* forwardIp = ip; unsigned step = 1; unsigned searchMatchNb = acceleration << LZ4_skipTrigger; do { @@ -998,12 +998,12 @@ FORCE_INLINE int LZ4_compress_generic( match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base); if (dict==usingExtDict) { - if (match < (const BYTE*)source) { + if (match < (const U8*)source) { refDelta = dictDelta; lowLimit = dictionary; } else { refDelta = 0; - lowLimit = (const BYTE*)source; + lowLimit = (const U8*)source; } } forwardH = LZ4_hashPosition(forwardIp, tableType); LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base); @@ -1026,9 +1026,9 @@ FORCE_INLINE int LZ4_compress_generic( int len = (int)litLength-RUN_MASK; *token = (RUN_MASK<= 255 ; len-=255) *op++ = 255; - *op++ = (BYTE)len; + *op++ = (U8)len; } - else *token = (BYTE)(litLength< matchlimit) limit = matchlimit; matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit); ip += MINMATCH + matchCode; if (ip==limit) { - unsigned const more = LZ4_count(ip, (const BYTE*)source, matchlimit); + unsigned const more = LZ4_count(ip, (const U8*)source, matchlimit); matchCode += more; ip += more; } @@ -1068,9 +1068,9 @@ _next_match: LZ4_write32(op, 0xFFFFFFFF); while (matchCode >= 4*255) op+=4, LZ4_write32(op, 0xFFFFFFFF), matchCode -= 4*255; op += matchCode / 255; - *op++ = (BYTE)(matchCode % 255); + *op++ = (U8)(matchCode % 255); } else - *token += (BYTE)(matchCode); + *token += (U8)(matchCode); } anchor = ip; @@ -1084,12 +1084,12 @@ _next_match: /* Test next position */ match = LZ4_getPosition(ip, cctx->hashTable, tableType, base); if (dict==usingExtDict) { - if (match < (const BYTE*)source) { + if (match < (const U8*)source) { refDelta = dictDelta; lowLimit = dictionary; } else { refDelta = 0; - lowLimit = (const BYTE*)source; + lowLimit = (const U8*)source; } } LZ4_putPosition(ip, cctx->hashTable, tableType, base); if ( ((dictIssue==dictSmall) ? (match>=lowRefLimit) : 1) @@ -1105,15 +1105,15 @@ _last_literals: /* Encode Last Literals */ { size_t const lastRun = (size_t)(iend - anchor); if ( (outputLimited) && /* Check output buffer overflow */ - ((op - (BYTE*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize) ) + ((op - (U8*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize) ) return 0; if (lastRun >= RUN_MASK) { size_t accumulator = lastRun - RUN_MASK; *op++ = RUN_MASK << ML_BITS; for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; - *op++ = (BYTE) accumulator; + *op++ = (U8) accumulator; } else { - *op++ = (BYTE)(lastRun<= 255 ; len-=255) *op++ = 255; - *op++ = (BYTE)len; + *op++ = (U8)len; } - else *token = (BYTE)(litLength<= 255) { matchLength-=255; *op++ = 255; } - *op++ = (BYTE)matchLength; + *op++ = (U8)matchLength; } - else *token += (BYTE)(matchLength); + else *token += (U8)(matchLength); } anchor = ip; @@ -1328,9 +1328,9 @@ _last_literals: size_t accumulator = lastRunSize - RUN_MASK; *op++ = RUN_MASK << ML_BITS; for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; - *op++ = (BYTE) accumulator; + *op++ = (U8) accumulator; } else { - *op++ = (BYTE)(lastRunSize<internal_donotuse; - const BYTE* p = (const BYTE*)dictionary; - const BYTE* const dictEnd = p + dictSize; - const BYTE* base; + const U8* p = (const U8*)dictionary; + const U8* const dictEnd = p + dictSize; + const U8* base; if ((dict->initCheck) || (dict->currentOffset > 1 GB)) /* Uninitialized structure, or reuse overflow */ LZ4_resetStream(LZ4_dict); @@ -1433,13 +1433,13 @@ int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize) } -static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, const BYTE* src) +static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, const U8* src) { if ((LZ4_dict->currentOffset > 0x80000000) || ((uptrval)LZ4_dict->currentOffset > (uptrval)src)) { /* address space overflow */ /* rescale hash table */ U32 const delta = LZ4_dict->currentOffset - 64 KB; - const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize; + const U8* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize; int i; for (i=0; ihashTable[i] < delta) LZ4_dict->hashTable[i]=0; @@ -1455,16 +1455,16 @@ static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, const BYTE* src) int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) { LZ4_stream_t_internal* streamPtr = &LZ4_stream->internal_donotuse; - const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; + const U8* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; - const BYTE* smallest = (const BYTE*) source; + const U8* smallest = (const U8*) source; if (streamPtr->initCheck) return 0; /* Uninitialized structure detected */ if ((streamPtr->dictSize>0) && (smallest>dictEnd)) smallest = dictEnd; LZ4_renormDictT(streamPtr, smallest); if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; /* Check overlapping input/dictionary space */ - { const BYTE* sourceEnd = (const BYTE*) source + inputSize; + { const U8* sourceEnd = (const U8*) source + inputSize; if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd)) { streamPtr->dictSize = (U32)(dictEnd - sourceEnd); if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB; @@ -1474,7 +1474,7 @@ int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, ch } /* prefix mode : source data follows dictionary */ - if (dictEnd == (const BYTE*)source) { + if (dictEnd == (const U8*)source) { int result; if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, dictSmall, acceleration); @@ -1491,7 +1491,7 @@ int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, ch result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, dictSmall, acceleration); else result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, noDictIssue, acceleration); - streamPtr->dictionary = (const BYTE*)source; + streamPtr->dictionary = (const U8*)source; streamPtr->dictSize = (U32)inputSize; streamPtr->currentOffset += (U32)inputSize; return result; @@ -1504,15 +1504,15 @@ int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* { LZ4_stream_t_internal* streamPtr = &LZ4_dict->internal_donotuse; int result; - const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; + const U8* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; - const BYTE* smallest = dictEnd; - if (smallest > (const BYTE*) source) smallest = (const BYTE*) source; + const U8* smallest = dictEnd; + if (smallest > (const U8*) source) smallest = (const U8*) source; LZ4_renormDictT(streamPtr, smallest); result = LZ4_compress_generic(streamPtr, source, dest, inputSize, 0, notLimited, byU32, usingExtDict, noDictIssue, 1); - streamPtr->dictionary = (const BYTE*)source; + streamPtr->dictionary = (const U8*)source; streamPtr->dictSize = (U32)inputSize; streamPtr->currentOffset += (U32)inputSize; @@ -1530,14 +1530,14 @@ int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize) { LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse; - const BYTE* const previousDictEnd = dict->dictionary + dict->dictSize; + const U8* const previousDictEnd = dict->dictionary + dict->dictSize; if ((U32)dictSize > 64 KB) dictSize = 64 KB; /* useless to define a dictionary > 64 KB */ if ((U32)dictSize > dict->dictSize) dictSize = dict->dictSize; memmove(safeBuffer, previousDictEnd - dictSize, dictSize); - dict->dictionary = (const BYTE*)safeBuffer; + dict->dictionary = (const U8*)safeBuffer; dict->dictSize = (U32)dictSize; return dictSize; @@ -1564,22 +1564,22 @@ FORCE_INLINE int LZ4_decompress_generic( int partialDecoding, /* full, partial */ int targetOutputSize, /* only used if partialDecoding==partial */ int dict, /* noDict, withPrefix64k, usingExtDict */ - const BYTE* const lowPrefix, /* == dest when no prefix */ - const BYTE* const dictStart, /* only if dict==usingExtDict */ + const U8* const lowPrefix, /* == dest when no prefix */ + const U8* const dictStart, /* only if dict==usingExtDict */ const size_t dictSize /* note : = 0 if noDict */ ) { /* Local Variables */ - const BYTE* ip = (const BYTE*) source; - const BYTE* const iend = ip + inputSize; + const U8* ip = (const U8*) source; + const U8* const iend = ip + inputSize; - BYTE* op = (BYTE*) dest; - BYTE* const oend = op + outputSize; - BYTE* cpy; - BYTE* oexit = op + targetOutputSize; - const BYTE* const lowLimit = lowPrefix - dictSize; + U8* op = (U8*) dest; + U8* const oend = op + outputSize; + U8* cpy; + U8* oexit = op + targetOutputSize; + const U8* const lowLimit = lowPrefix - dictSize; - const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize; + const U8* const dictEnd = (const U8*)dictStart + dictSize; const unsigned dec32table[] = {0, 1, 2, 1, 4, 4, 4, 4}; const int dec64table[] = {0, 0, 0, -1, 0, 1, 2, 3}; @@ -1595,7 +1595,7 @@ FORCE_INLINE int LZ4_decompress_generic( /* Main Loop : decode sequences */ while (1) { size_t length; - const BYTE* match; + const U8* match; size_t offset; /* get literal length */ @@ -1664,8 +1664,8 @@ FORCE_INLINE int LZ4_decompress_generic( memcpy(op, dictEnd - copySize, copySize); op += copySize; if (restSize > (size_t)(op-lowPrefix)) { /* overlap copy */ - BYTE* const endOfMatch = op + restSize; - const BYTE* copyFrom = lowPrefix; + U8* const endOfMatch = op + restSize; + const U8* copyFrom = lowPrefix; while (op < endOfMatch) *op++ = *copyFrom++; } else { memcpy(op, lowPrefix, restSize); @@ -1689,7 +1689,7 @@ FORCE_INLINE int LZ4_decompress_generic( op += 8; if (unlikely(cpy>oend-12)) { - BYTE* const oCopyLimit = oend-(WILDCOPYLENGTH-1); + U8* const oCopyLimit = oend-(WILDCOPYLENGTH-1); if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */ if (op < oCopyLimit) { LZ4_wildCopy(op, match, oCopyLimit); @@ -1718,17 +1718,17 @@ _output_error: int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize) { - return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, (BYTE*)dest, NULL, 0); + return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, (U8*)dest, NULL, 0); } int LZ4_decompress_safe_partial(const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize) { - return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, partial, targetOutputSize, noDict, (BYTE*)dest, NULL, 0); + return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, partial, targetOutputSize, noDict, (U8*)dest, NULL, 0); } int LZ4_decompress_fast(const char* source, char* dest, int originalSize) { - return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)(dest - 64 KB), NULL, 64 KB); + return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (U8*)(dest - 64 KB), NULL, 64 KB); } @@ -1762,7 +1762,7 @@ int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dicti { LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; lz4sd->prefixSize = (size_t) dictSize; - lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize; + lz4sd->prefixEnd = (const U8*) dictionary + dictSize; lz4sd->externalDict = NULL; lz4sd->extDictSize = 0; return 1; @@ -1780,7 +1780,7 @@ int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const ch LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; int result; - if (lz4sd->prefixEnd == (BYTE*)dest) { + if (lz4sd->prefixEnd == (U8*)dest) { result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); @@ -1792,10 +1792,10 @@ int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const ch lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, - usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize); + usingExtDict, (U8*)dest, lz4sd->externalDict, lz4sd->extDictSize); if (result <= 0) return result; lz4sd->prefixSize = result; - lz4sd->prefixEnd = (BYTE*)dest + result; + lz4sd->prefixEnd = (U8*)dest + result; } return result; @@ -1806,7 +1806,7 @@ int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const ch LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; int result; - if (lz4sd->prefixEnd == (BYTE*)dest) { + if (lz4sd->prefixEnd == (U8*)dest) { result = LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); @@ -1818,10 +1818,10 @@ int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const ch lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; result = LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, - usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize); + usingExtDict, (U8*)dest, lz4sd->externalDict, lz4sd->extDictSize); if (result <= 0) return result; lz4sd->prefixSize = originalSize; - lz4sd->prefixEnd = (BYTE*)dest + originalSize; + lz4sd->prefixEnd = (U8*)dest + originalSize; } return result; @@ -1838,13 +1838,13 @@ Advanced decoding functions : FORCE_INLINE int LZ4_decompress_usingDict_generic(const char* source, char* dest, int compressedSize, int maxOutputSize, int safe, const char* dictStart, int dictSize) { if (dictSize==0) - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest, NULL, 0); + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (U8*)dest, NULL, 0); if (dictStart+dictSize == dest) { if (dictSize >= (int)(64 KB - 1)) - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, withPrefix64k, (BYTE*)dest-64 KB, NULL, 0); - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest-dictSize, NULL, 0); + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, withPrefix64k, (U8*)dest-64 KB, NULL, 0); + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (U8*)dest-dictSize, NULL, 0); } - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, usingExtDict, (U8*)dest, (const U8*)dictStart, dictSize); } int LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize) @@ -1860,7 +1860,7 @@ int LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSi /* debug function */ int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize) { - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, (U8*)dest, (const U8*)dictStart, dictSize); } @@ -1889,7 +1889,7 @@ int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int LZ4_sizeofStreamState() { return LZ4_STREAMSIZE; } -static void LZ4_init(LZ4_stream_t* lz4ds, BYTE* base) +static void LZ4_init(LZ4_stream_t* lz4ds, U8* base) { MEM_INIT(lz4ds, 0, sizeof(LZ4_stream_t)); lz4ds->internal_donotuse.bufferStart = base; @@ -1898,14 +1898,14 @@ static void LZ4_init(LZ4_stream_t* lz4ds, BYTE* base) int LZ4_resetStreamState(void* state, char* inputBuffer) { if ((((uptrval)state) & 3) != 0) return 1; /* Error : pointer is not aligned on 4-bytes boundary */ - LZ4_init((LZ4_stream_t*)state, (BYTE*)inputBuffer); + LZ4_init((LZ4_stream_t*)state, (U8*)inputBuffer); return 0; } void* LZ4_create (char* inputBuffer) { LZ4_stream_t* lz4ds = (LZ4_stream_t*)ALLOCATOR(8, sizeof(LZ4_stream_t)); - LZ4_init (lz4ds, (BYTE*)inputBuffer); + LZ4_init (lz4ds, (U8*)inputBuffer); return lz4ds; } @@ -1920,12 +1920,12 @@ char* LZ4_slideInputBuffer (void* LZ4_Data) int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize) { - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB); + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, withPrefix64k, (U8*)dest - 64 KB, NULL, 64 KB); } int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize) { - return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB); + return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (U8*)dest - 64 KB, NULL, 64 KB); } #endif /* LZ4_COMMONDEFS_ONLY */ @@ -2294,20 +2294,20 @@ static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr) ***************************************/ FORCE_INLINE int LZ4HC_BinTree_InsertAndGetAllMatches ( LZ4HC_CCtx_internal* ctx, - const BYTE* const ip, - const BYTE* const iHighLimit, + const U8* const ip, + const U8* const iHighLimit, size_t best_mlen, LZ4HC_match_t* matches, int* matchNum) { U16* const chainTable = ctx->chainTable; U32* const HashTable = ctx->hashTable; - const BYTE* const base = ctx->base; + const U8* const base = ctx->base; const U32 dictLimit = ctx->dictLimit; const U32 current = (U32)(ip - base); const U32 lowLimit = (ctx->lowLimit + MAX_DISTANCE > current) ? ctx->lowLimit : current - (MAX_DISTANCE - 1); - const BYTE* const dictBase = ctx->dictBase; - const BYTE* match; + const U8* const dictBase = ctx->dictBase; + const U8* match; int nbAttempts = ctx->searchNum; int mnum = 0; U16 *ptr0, *ptr1, delta0, delta1; @@ -2332,7 +2332,7 @@ FORCE_INLINE int LZ4HC_BinTree_InsertAndGetAllMatches ( match = base + matchIndex; matchLength = LZ4_count(ip, match, iHighLimit); } else { - const BYTE* vLimit = ip + (dictLimit - matchIndex); + const U8* vLimit = ip + (dictLimit - matchIndex); match = dictBase + matchIndex; if (vLimit > iHighLimit) vLimit = iHighLimit; matchLength = LZ4_count(ip, match, vLimit); @@ -2382,9 +2382,9 @@ FORCE_INLINE int LZ4HC_BinTree_InsertAndGetAllMatches ( } -FORCE_INLINE void LZ4HC_updateBinTree(LZ4HC_CCtx_internal* ctx, const BYTE* const ip, const BYTE* const iHighLimit) +FORCE_INLINE void LZ4HC_updateBinTree(LZ4HC_CCtx_internal* ctx, const U8* const ip, const U8* const iHighLimit) { - const BYTE* const base = ctx->base; + const U8* const base = ctx->base; const U32 target = (U32)(ip - base); U32 idx = ctx->nextToUpdate; while(idx < target) @@ -2395,7 +2395,7 @@ FORCE_INLINE void LZ4HC_updateBinTree(LZ4HC_CCtx_internal* ctx, const BYTE* cons /** Tree updater, providing best match */ FORCE_INLINE int LZ4HC_BinTree_GetAllMatches ( LZ4HC_CCtx_internal* ctx, - const BYTE* const ip, const BYTE* const iHighLimit, + const U8* const ip, const U8* const iHighLimit, size_t best_mlen, LZ4HC_match_t* matches, const int fullUpdate) { int mnum = 0; @@ -2416,7 +2416,7 @@ FORCE_INLINE int LZ4HC_BinTree_GetAllMatches ( opt[pos].price = (int)cost; \ } -FORCE_INLINE int LZ4HC_encodeSequence ( const BYTE** ip, BYTE** op, const BYTE** anchor, int matchLength, const BYTE* const match, limitedOutput_directive limit, BYTE* oend); +FORCE_INLINE int LZ4HC_encodeSequence ( const U8** ip, U8** op, const U8** anchor, int matchLength, const U8* const match, limitedOutput_directive limit, U8* oend); static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx, @@ -2432,13 +2432,13 @@ static int LZ4HC_compress_optimal ( LZ4HC_optimal_t opt[LZ4_OPT_NUM + 1]; /* this uses a bit too much stack memory to my taste ... */ LZ4HC_match_t matches[LZ4_OPT_NUM + 1]; - const BYTE* ip = (const BYTE*) source; - const BYTE* anchor = ip; - const BYTE* const iend = ip + inputSize; - const BYTE* const mflimit = iend - MFLIMIT; - const BYTE* const matchlimit = (iend - LASTLITERALS); - BYTE* op = (BYTE*) dest; - BYTE* const oend = op + maxOutputSize; + const U8* ip = (const U8*) source; + const U8* anchor = ip; + const U8* const iend = ip + inputSize; + const U8* const mflimit = iend - MFLIMIT; + const U8* const matchlimit = (iend - LASTLITERALS); + U8* op = (U8*) dest; + U8* const oend = op + maxOutputSize; /* init */ if (sufficient_len >= LZ4_OPT_NUM) sufficient_len = LZ4_OPT_NUM-1; @@ -2479,7 +2479,7 @@ static int LZ4HC_compress_optimal ( /* check further positions */ opt[0].mlen = opt[1].mlen = 1; for (cur = 1; cur <= last_pos; cur++) { - const BYTE* const curPtr = ip + cur; + const U8* const curPtr = ip + cur; /* establish baseline price if cur is literal */ { size_t price, litlen; @@ -2567,8 +2567,8 @@ encode: /* cur, last_pos, best_mlen, best_off must be set */ /* Encode Last Literals */ { int lastRun = (int)(iend - anchor); if ((limit) && (((char*)op - dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize)) return 0; /* Check output limit */ - if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK< 254 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; } - else *op++ = (BYTE)(lastRun<=(int)RUN_MASK) { *op++=(RUN_MASK< 254 ; lastRun-=255) *op++ = 255; *op++ = (U8) lastRun; } + else *op++ = (U8)(lastRun<hashTable, 0, sizeof(hc4->hashTable)); MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable)); @@ -2650,11 +2650,11 @@ static void LZ4HC_init (LZ4HC_CCtx_internal* hc4, const BYTE* start) /* Update chains up to ip (excluded) */ -FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip) +FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const U8* ip) { U16* const chainTable = hc4->chainTable; U32* const hashTable = hc4->hashTable; - const BYTE* const base = hc4->base; + const U8* const base = hc4->base; U32 const target = (U32)(ip - base); U32 idx = hc4->nextToUpdate; @@ -2672,14 +2672,14 @@ FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip) FORCE_INLINE int LZ4HC_InsertAndFindBestMatch (LZ4HC_CCtx_internal* hc4, /* Index table will be updated */ - const BYTE* ip, const BYTE* const iLimit, - const BYTE** matchpos, + const U8* ip, const U8* const iLimit, + const U8** matchpos, const int maxNbAttempts) { U16* const chainTable = hc4->chainTable; U32* const HashTable = hc4->hashTable; - const BYTE* const base = hc4->base; - const BYTE* const dictBase = hc4->dictBase; + const U8* const base = hc4->base; + const U8* const dictBase = hc4->dictBase; const U32 dictLimit = hc4->dictLimit; const U32 lowLimit = (hc4->lowLimit + 64 KB > (U32)(ip-base)) ? hc4->lowLimit : (U32)(ip - base) - (64 KB - 1); U32 matchIndex; @@ -2693,7 +2693,7 @@ FORCE_INLINE int LZ4HC_InsertAndFindBestMatch (LZ4HC_CCtx_internal* hc4, /* In while ((matchIndex>=lowLimit) && (nbAttempts)) { nbAttempts--; if (matchIndex >= dictLimit) { - const BYTE* const match = base + matchIndex; + const U8* const match = base + matchIndex; if (*(match+ml) == *(ip+ml) && (LZ4_read32(match) == LZ4_read32(ip))) { @@ -2701,10 +2701,10 @@ FORCE_INLINE int LZ4HC_InsertAndFindBestMatch (LZ4HC_CCtx_internal* hc4, /* In if (mlt > ml) { ml = mlt; *matchpos = match; } } } else { - const BYTE* const match = dictBase + matchIndex; + const U8* const match = dictBase + matchIndex; if (LZ4_read32(match) == LZ4_read32(ip)) { size_t mlt; - const BYTE* vLimit = ip + (dictLimit - matchIndex); + const U8* vLimit = ip + (dictLimit - matchIndex); if (vLimit > iLimit) vLimit = iLimit; mlt = LZ4_count(ip+MINMATCH, match+MINMATCH, vLimit) + MINMATCH; if ((ip+mlt == vLimit) && (vLimit < iLimit)) @@ -2721,21 +2721,21 @@ FORCE_INLINE int LZ4HC_InsertAndFindBestMatch (LZ4HC_CCtx_internal* hc4, /* In FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch ( LZ4HC_CCtx_internal* hc4, - const BYTE* const ip, - const BYTE* const iLowLimit, - const BYTE* const iHighLimit, + const U8* const ip, + const U8* const iLowLimit, + const U8* const iHighLimit, int longest, - const BYTE** matchpos, - const BYTE** startpos, + const U8** matchpos, + const U8** startpos, const int maxNbAttempts) { U16* const chainTable = hc4->chainTable; U32* const HashTable = hc4->hashTable; - const BYTE* const base = hc4->base; + const U8* const base = hc4->base; const U32 dictLimit = hc4->dictLimit; - const BYTE* const lowPrefixPtr = base + dictLimit; + const U8* const lowPrefixPtr = base + dictLimit; const U32 lowLimit = (hc4->lowLimit + 64 KB > (U32)(ip-base)) ? hc4->lowLimit : (U32)(ip - base) - (64 KB - 1); - const BYTE* const dictBase = hc4->dictBase; + const U8* const dictBase = hc4->dictBase; U32 matchIndex; int nbAttempts = maxNbAttempts; int delta = (int)(ip-iLowLimit); @@ -2748,7 +2748,7 @@ FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch ( while ((matchIndex>=lowLimit) && (nbAttempts)) { nbAttempts--; if (matchIndex >= dictLimit) { - const BYTE* matchPtr = base + matchIndex; + const U8* matchPtr = base + matchIndex; if (*(iLowLimit + longest) == *(matchPtr - delta + longest)) { if (LZ4_read32(matchPtr) == LZ4_read32(ip)) { int mlt = MINMATCH + LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit); @@ -2767,11 +2767,11 @@ FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch ( *startpos = ip+back; } } } } else { - const BYTE* const matchPtr = dictBase + matchIndex; + const U8* const matchPtr = dictBase + matchIndex; if (LZ4_read32(matchPtr) == LZ4_read32(ip)) { size_t mlt; int back=0; - const BYTE* vLimit = ip + (dictLimit - matchIndex); + const U8* vLimit = ip + (dictLimit - matchIndex); if (vLimit > iHighLimit) vLimit = iHighLimit; mlt = LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH; if ((ip+mlt == vLimit) && (vLimit < iHighLimit)) @@ -2798,10 +2798,10 @@ static unsigned debug = 0; /* LZ4HC_encodeSequence() : * @return : 0 if ok, * 1 if buffer issue detected */ -FORCE_INLINE int LZ4HC_encodeSequence ( const BYTE** ip, BYTE** op, const BYTE** anchor, int matchLength, const BYTE* const match, limitedOutput_directive limit, BYTE* oend) +FORCE_INLINE int LZ4HC_encodeSequence ( const U8** ip, U8** op, const U8** anchor, int matchLength, const U8* const match, limitedOutput_directive limit, U8* oend) { size_t length; - BYTE* token; + U8* token; #if LZ4HC_DEBUG if (debug) printf("literal : %u -- match : %u -- offset : %u\n", (U32)(*ip - *anchor), (U32)matchLength, (U32)(*ip-match)); @@ -2815,9 +2815,9 @@ FORCE_INLINE int LZ4HC_encodeSequence ( const BYTE** ip, BYTE** op, const BYTE** size_t len = length - RUN_MASK; *token = (RUN_MASK << ML_BITS); for(; len >= 255 ; len -= 255) *(*op)++ = 255; - *(*op)++ = (BYTE)len; + *(*op)++ = (U8)len; } else { - *token = (BYTE)(length << ML_BITS); + *token = (U8)(length << ML_BITS); } /* Copy Literals */ @@ -2835,9 +2835,9 @@ FORCE_INLINE int LZ4HC_encodeSequence ( const BYTE** ip, BYTE** op, const BYTE** length -= ML_MASK; for(; length >= 510 ; length -= 510) { *(*op)++ = 255; *(*op)++ = 255; } if (length >= 255) { length -= 255; *(*op)++ = 255; } - *(*op)++ = (BYTE)length; + *(*op)++ = (U8)length; } else { - *token += (BYTE)(length); + *token += (U8)(length); } /* Prepare next loop */ @@ -2862,24 +2862,24 @@ static int LZ4HC_compress_hashChain ( { const int inputSize = *srcSizePtr; - const BYTE* ip = (const BYTE*) source; - const BYTE* anchor = ip; - const BYTE* const iend = ip + inputSize; - const BYTE* const mflimit = iend - MFLIMIT; - const BYTE* const matchlimit = (iend - LASTLITERALS); + const U8* ip = (const U8*) source; + const U8* anchor = ip; + const U8* const iend = ip + inputSize; + const U8* const mflimit = iend - MFLIMIT; + const U8* const matchlimit = (iend - LASTLITERALS); - BYTE* optr = (BYTE*) dest; - BYTE* op = (BYTE*) dest; - BYTE* oend = op + maxOutputSize; + U8* optr = (U8*) dest; + U8* op = (U8*) dest; + U8* oend = op + maxOutputSize; int ml, ml2, ml3, ml0; - const BYTE* ref = NULL; - const BYTE* start2 = NULL; - const BYTE* ref2 = NULL; - const BYTE* start3 = NULL; - const BYTE* ref3 = NULL; - const BYTE* start0; - const BYTE* ref0; + const U8* ref = NULL; + const U8* start2 = NULL; + const U8* ref2 = NULL; + const U8* start3 = NULL; + const U8* ref3 = NULL; + const U8* start0; + const U8* ref0; /* init */ *srcSizePtr = 0; @@ -3049,9 +3049,9 @@ _last_literals: size_t accumulator = lastRunSize - RUN_MASK; *op++ = (RUN_MASK << ML_BITS); for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255; - *op++ = (BYTE) accumulator; + *op++ = (U8) accumulator; } else { - *op++ = (BYTE)(lastRunSize << ML_BITS); + *op++ = (U8)(lastRunSize << ML_BITS); } memcpy(op, anchor, lastRunSize); op += lastRunSize; @@ -3113,7 +3113,7 @@ int LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int src { LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)state)->internal_donotuse; if (((size_t)(state)&(sizeof(void*)-1)) != 0) return 0; /* Error : state is not aligned for pointers (32 or 64 bits) */ - LZ4HC_init (ctx, (const BYTE*)src); + LZ4HC_init (ctx, (const U8*)src); if (dstCapacity < LZ4_compressBound(srcSize)) return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, limitedOutput); else @@ -3141,7 +3141,7 @@ int LZ4_compress_HC(const char* src, char* dst, int srcSize, int dstCapacity, in int LZ4_compress_HC_destSize(void* LZ4HC_Data, const char* source, char* dest, int* sourceSizePtr, int targetDestSize, int cLevel) { LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse; - LZ4HC_init(ctx, (const BYTE*) source); + LZ4HC_init(ctx, (const U8*) source); return LZ4HC_compress_generic(ctx, source, dest, sourceSizePtr, targetDestSize, cLevel, limitedDestSize); } @@ -3172,8 +3172,8 @@ int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, const char* dictionary, int dictionary += dictSize - 64 KB; dictSize = 64 KB; } - LZ4HC_init (ctxPtr, (const BYTE*)dictionary); - ctxPtr->end = (const BYTE*)dictionary + dictSize; + LZ4HC_init (ctxPtr, (const U8*)dictionary); + ctxPtr->end = (const U8*)dictionary + dictSize; if (ctxPtr->compressionLevel >= LZ4HC_CLEVEL_OPT_MIN) LZ4HC_updateBinTree(ctxPtr, ctxPtr->end - MFLIMIT, ctxPtr->end - LASTLITERALS); else @@ -3184,7 +3184,7 @@ int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, const char* dictionary, int /* compression */ -static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock) +static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const U8* newBlock) { if (ctxPtr->compressionLevel >= LZ4HC_CLEVEL_OPT_MIN) LZ4HC_updateBinTree(ctxPtr, ctxPtr->end - MFLIMIT, ctxPtr->end - LASTLITERALS); @@ -3207,7 +3207,7 @@ static int LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr, { LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse; /* auto-init if forgotten */ - if (ctxPtr->base == NULL) LZ4HC_init (ctxPtr, (const BYTE*) src); + if (ctxPtr->base == NULL) LZ4HC_init (ctxPtr, (const U8*) src); /* Check overflow */ if ((size_t)(ctxPtr->end - ctxPtr->base) > 2 GB) { @@ -3217,13 +3217,13 @@ static int LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr, } /* Check if blocks follow each other */ - if ((const BYTE*)src != ctxPtr->end) LZ4HC_setExternalDict(ctxPtr, (const BYTE*)src); + if ((const U8*)src != ctxPtr->end) LZ4HC_setExternalDict(ctxPtr, (const U8*)src); /* Check overlapping input/dictionary space */ - { const BYTE* sourceEnd = (const BYTE*) src + *srcSizePtr; - const BYTE* const dictBegin = ctxPtr->dictBase + ctxPtr->lowLimit; - const BYTE* const dictEnd = ctxPtr->dictBase + ctxPtr->dictLimit; - if ((sourceEnd > dictBegin) && ((const BYTE*)src < dictEnd)) { + { const U8* sourceEnd = (const U8*) src + *srcSizePtr; + const U8* const dictBegin = ctxPtr->dictBase + ctxPtr->lowLimit; + const U8* const dictEnd = ctxPtr->dictBase + ctxPtr->dictLimit; + if ((sourceEnd > dictBegin) && ((const U8*)src < dictEnd)) { if (sourceEnd > dictEnd) sourceEnd = dictEnd; ctxPtr->lowLimit = (U32)(sourceEnd - ctxPtr->dictBase); if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4) ctxPtr->lowLimit = ctxPtr->dictLimit; @@ -3244,7 +3244,7 @@ int LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, int LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int* srcSizePtr, int targetDestSize) { LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse; - if (ctxPtr->compressionLevel >= LZ4HC_CLEVEL_OPT_MIN) LZ4HC_init(ctxPtr, (const BYTE*)src); /* not compatible with btopt implementation */ + if (ctxPtr->compressionLevel >= LZ4HC_CLEVEL_OPT_MIN) LZ4HC_init(ctxPtr, (const U8*)src); /* not compatible with btopt implementation */ return LZ4_compressHC_continue_generic(LZ4_streamHCPtr, src, dst, srcSizePtr, targetDestSize, limitedDestSize); } @@ -3261,7 +3261,7 @@ int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictS if (dictSize > prefixSize) dictSize = prefixSize; memmove(safeBuffer, streamPtr->end - dictSize, dictSize); { U32 const endIndex = (U32)(streamPtr->end - streamPtr->base); - streamPtr->end = (const BYTE*)safeBuffer + dictSize; + streamPtr->end = (const U8*)safeBuffer + dictSize; streamPtr->base = streamPtr->end - endIndex; streamPtr->dictLimit = endIndex - dictSize; streamPtr->lowLimit = endIndex - dictSize; @@ -3295,8 +3295,8 @@ int LZ4_resetStreamStateHC(void* state, char* inputBuffer) { LZ4HC_CCtx_internal *ctx = &((LZ4_streamHC_t*)state)->internal_donotuse; if ((((size_t)state) & (sizeof(void*)-1)) != 0) return 1; /* Error : pointer is not aligned for pointer (32 or 64 bits) */ - LZ4HC_init(ctx, (const BYTE*)inputBuffer); - ctx->inputBuffer = (BYTE*)inputBuffer; + LZ4HC_init(ctx, (const U8*)inputBuffer); + ctx->inputBuffer = (U8*)inputBuffer; return 0; } @@ -3304,8 +3304,8 @@ void* LZ4_createHC (char* inputBuffer) { LZ4_streamHC_t* hc4 = (LZ4_streamHC_t*)ALLOCATOR(1, sizeof(LZ4_streamHC_t)); if (hc4 == NULL) return NULL; /* not enough memory */ - LZ4HC_init (&hc4->internal_donotuse, (const BYTE*)inputBuffer); - hc4->internal_donotuse.inputBuffer = (BYTE*)inputBuffer; + LZ4HC_init (&hc4->internal_donotuse, (const U8*)inputBuffer); + hc4->internal_donotuse.inputBuffer = (U8*)inputBuffer; return hc4; } diff --git a/tools/rasm/lzsa-master/src/dictionary.c b/tools/rasm/lzsa-master/src/dictionary.c new file mode 100644 index 0000000..fbc4f52 --- /dev/null +++ b/tools/rasm/lzsa-master/src/dictionary.c @@ -0,0 +1,101 @@ +/* + * dictionary.c - dictionary implementation + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#include +#include +#include "format.h" +#include "lib.h" + +/** + * Load dictionary contents + * + * @param pszDictionaryFilename name of dictionary file, or NULL for none + * @param ppDictionaryData pointer to returned dictionary contents, or NULL for none + * @param pDictionaryDataSize pointer to returned size of dictionary contents, or 0 + * + * @return LZSA_OK for success, or an error value from lzsa_status_t + */ +int lzsa_dictionary_load(const char *pszDictionaryFilename, void **ppDictionaryData, int *pDictionaryDataSize) { + unsigned char *pDictionaryData = NULL; + int nDictionaryDataSize = 0; + + if (pszDictionaryFilename) { + pDictionaryData = (unsigned char *)malloc(BLOCK_SIZE); + if (!pDictionaryData) { + return LZSA_ERROR_MEMORY; + } + + FILE *pDictionaryFile = fopen(pszDictionaryFilename, "rb"); + if (!pDictionaryFile) { + free(pDictionaryData); + pDictionaryData = NULL; + return LZSA_ERROR_DICTIONARY; + } + + fseek(pDictionaryFile, 0, SEEK_END); +#ifdef _WIN32 + __int64 nDictionaryFileSize = _ftelli64(pDictionaryFile); +#else + off_t nDictionaryFileSize = ftello(pDictionaryFile); +#endif + if (nDictionaryFileSize > BLOCK_SIZE) { + /* Use the last BLOCK_SIZE bytes of the dictionary */ + fseek(pDictionaryFile, -BLOCK_SIZE, SEEK_END); + } + else { + fseek(pDictionaryFile, 0, SEEK_SET); + } + + nDictionaryDataSize = (int)fread(pDictionaryData, 1, BLOCK_SIZE, pDictionaryFile); + if (nDictionaryDataSize < 0) + nDictionaryDataSize = 0; + + fclose(pDictionaryFile); + pDictionaryFile = NULL; + } + + *ppDictionaryData = pDictionaryData; + *pDictionaryDataSize = nDictionaryDataSize; + return LZSA_OK; +} + +/** + * Free dictionary contents + * + * @param ppDictionaryData pointer to pointer to dictionary contents + */ +void lzsa_dictionary_free(void **ppDictionaryData) { + if (*ppDictionaryData) { + free(*ppDictionaryData); + *ppDictionaryData = NULL; + } +} diff --git a/tools/rasm/lzsa-master/src/dictionary.h b/tools/rasm/lzsa-master/src/dictionary.h new file mode 100644 index 0000000..a363564 --- /dev/null +++ b/tools/rasm/lzsa-master/src/dictionary.h @@ -0,0 +1,64 @@ +/* + * dictionary.h - dictionary definitions + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#ifndef _DICTIONARY_H +#define _DICTIONARY_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Load dictionary contents + * + * @param pszDictionaryFilename name of dictionary file, or NULL for none + * @param ppDictionaryData pointer to returned dictionary contents, or NULL for none + * @param pDictionaryDataSize pointer to returned size of dictionary contents, or 0 + * + * @return LZSA_OK for success, or an error value from lzsa_status_t + */ +int lzsa_dictionary_load(const char *pszDictionaryFilename, void **ppDictionaryData, int *pDictionaryDataSize); + +/** + * Free dictionary contents + * + * @param ppDictionaryData pointer to pointer to dictionary contents + */ +void lzsa_dictionary_free(void **ppDictionaryData); + +#ifdef __cplusplus +} +#endif + +#endif /* _DICTIONARY_H */ diff --git a/tools/rasm/lzsa-master/src/expand_block_v1.c b/tools/rasm/lzsa-master/src/expand_block_v1.c new file mode 100644 index 0000000..c248fb3 --- /dev/null +++ b/tools/rasm/lzsa-master/src/expand_block_v1.c @@ -0,0 +1,224 @@ +/* + * expand_block_v1.c - LZSA1 block decompressor implementation + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#include +#include +#include "format.h" +#include "expand_block_v1.h" + +#ifdef _MSC_VER +#define FORCE_INLINE __forceinline +#else /* _MSC_VER */ +#define FORCE_INLINE __attribute__((always_inline)) +#endif /* _MSC_VER */ + +static inline FORCE_INLINE int lzsa_build_literals_len_v1(const unsigned char **ppInBlock, const unsigned char *pInBlockEnd, unsigned int *nLiterals) { + unsigned int nByte; + const unsigned char *pInBlock = *ppInBlock; + + if (pInBlock < pInBlockEnd) { + nByte = *pInBlock++; + (*nLiterals) += nByte; + + if (nByte == 250) { + if (pInBlock < pInBlockEnd) { + (*nLiterals) = 256 + ((unsigned int)*pInBlock++); + } + else { + return -1; + } + } + else if (nByte == 249) { + if ((pInBlock + 1) < pInBlockEnd) { + (*nLiterals) = ((unsigned int)*pInBlock++); + (*nLiterals) |= (((unsigned int)*pInBlock++) << 8); + } + else { + return -1; + } + } + + *ppInBlock = pInBlock; + return 0; + } + else { + return -1; + } +} + +static inline FORCE_INLINE int lzsa_build_match_len_v1(const unsigned char **ppInBlock, const unsigned char *pInBlockEnd, unsigned int *nMatchLen) { + unsigned int nByte; + const unsigned char *pInBlock = *ppInBlock; + + if (pInBlock < pInBlockEnd) { + nByte = *pInBlock++; + (*nMatchLen) += nByte; + + if (nByte == 239) { + if (pInBlock < pInBlockEnd) { + (*nMatchLen) = 256 + ((unsigned int)*pInBlock++); + } + else { + return -1; + } + } + else if (nByte == 238) { + if ((pInBlock + 1) < pInBlockEnd) { + (*nMatchLen) = ((unsigned int)*pInBlock++); + (*nMatchLen) |= (((unsigned int)*pInBlock++) << 8); + } + else { + return -1; + } + } + + *ppInBlock = pInBlock; + return 0; + } + else { + return -1; + } +} + +/** + * Decompress one LZSA1 data block + * + * @param pInBlock pointer to compressed data + * @param nBlockSize size of compressed data, in bytes + * @param pOutData pointer to output decompression buffer (previously decompressed bytes + room for decompressing this block) + * @param nOutDataOffset starting index of where to store decompressed bytes in output buffer (and size of previously decompressed bytes) + * @param nBlockMaxSize total size of output decompression buffer, in bytes + * + * @return size of decompressed data in bytes, or -1 for error + */ +int lzsa_decompressor_expand_block_v1(const unsigned char *pInBlock, int nBlockSize, unsigned char *pOutData, int nOutDataOffset, int nBlockMaxSize) { + const unsigned char *pInBlockEnd = pInBlock + nBlockSize; + unsigned char *pCurOutData = pOutData + nOutDataOffset; + const unsigned char *pOutDataEnd = pCurOutData + nBlockMaxSize; + const unsigned char *pOutDataFastEnd = pOutDataEnd - 18; + + while (pInBlock < pInBlockEnd) { + const unsigned char token = *pInBlock++; + unsigned int nLiterals = (unsigned int)((token & 0x70) >> 4); + + if (nLiterals != LITERALS_RUN_LEN_V1 && (pInBlock + 8) <= pInBlockEnd && pCurOutData < pOutDataFastEnd) { + memcpy(pCurOutData, pInBlock, 8); + pInBlock += nLiterals; + pCurOutData += nLiterals; + } + else { + if (nLiterals == LITERALS_RUN_LEN_V1) { + if (lzsa_build_literals_len_v1(&pInBlock, pInBlockEnd, &nLiterals)) + return -1; + } + + if (nLiterals != 0) { + if ((pInBlock + nLiterals) <= pInBlockEnd && + (pCurOutData + nLiterals) <= pOutDataEnd) { + memcpy(pCurOutData, pInBlock, nLiterals); + pInBlock += nLiterals; + pCurOutData += nLiterals; + } + else { + return -1; + } + } + } + + if ((pInBlock + 1) < pInBlockEnd) { /* The last token in the block does not include match information */ + unsigned int nMatchOffset; + + nMatchOffset = ((unsigned int)(*pInBlock++)) ^ 0xff; + if (token & 0x80) { + nMatchOffset |= (((unsigned int)(*pInBlock++)) << 8) ^ 0xff00; + } + nMatchOffset++; + + const unsigned char *pSrc = pCurOutData - nMatchOffset; + if (pSrc >= pOutData) { + unsigned int nMatchLen = (unsigned int)(token & 0x0f); + if (nMatchLen != MATCH_RUN_LEN_V1 && nMatchOffset >= 8 && pCurOutData < pOutDataFastEnd && (pSrc + 18) <= pOutDataEnd) { + memcpy(pCurOutData, pSrc, 8); + memcpy(pCurOutData + 8, pSrc + 8, 8); + memcpy(pCurOutData + 16, pSrc + 16, 2); + pCurOutData += (MIN_MATCH_SIZE_V1 + nMatchLen); + } + else { + nMatchLen += MIN_MATCH_SIZE_V1; + if (nMatchLen == (MATCH_RUN_LEN_V1 + MIN_MATCH_SIZE_V1)) { + if (lzsa_build_match_len_v1(&pInBlock, pInBlockEnd, &nMatchLen)) + return -1; + if (nMatchLen == 0) + break; + } + + if ((pSrc + nMatchLen) <= pOutDataEnd) { + if ((pCurOutData + nMatchLen) <= pOutDataEnd) { + /* Do a deterministic, left to right byte copy instead of memcpy() so as to handle overlaps */ + + if (nMatchOffset >= 16 && (pCurOutData + nMatchLen) < (pOutDataFastEnd - 15)) { + const unsigned char *pCopySrc = pSrc; + unsigned char *pCopyDst = pCurOutData; + const unsigned char *pCopyEndDst = pCurOutData + nMatchLen; + + do { + memcpy(pCopyDst, pCopySrc, 16); + pCopySrc += 16; + pCopyDst += 16; + } while (pCopyDst < pCopyEndDst); + + pCurOutData += nMatchLen; + } + else { + while (nMatchLen) { + *pCurOutData++ = *pSrc++; + nMatchLen--; + } + } + } + else { + return -1; + } + } + else { + return -1; + } + } + } + else { + return -1; + } + } + } + + return (int)(pCurOutData - (pOutData + nOutDataOffset)); +} diff --git a/tools/rasm/lzsa-master/src/expand_block_v1.h b/tools/rasm/lzsa-master/src/expand_block_v1.h new file mode 100644 index 0000000..a1d5651 --- /dev/null +++ b/tools/rasm/lzsa-master/src/expand_block_v1.h @@ -0,0 +1,49 @@ +/* + * expand_block_v1.h - LZSA1 block decompressor definitions + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#ifndef _EXPAND_BLOCK_V1_H +#define _EXPAND_BLOCK_V1_H + +/** + * Decompress one LZSA1 data block + * + * @param pInBlock pointer to compressed data + * @param nBlockSize size of compressed data, in bytes + * @param pOutData pointer to output decompression buffer (previously decompressed bytes + room for decompressing this block) + * @param nOutDataOffset starting index of where to store decompressed bytes in output buffer (and size of previously decompressed bytes) + * @param nBlockMaxSize total size of output decompression buffer, in bytes + * + * @return size of decompressed data in bytes, or -1 for error + */ +int lzsa_decompressor_expand_block_v1(const unsigned char *pInBlock, int nBlockSize, unsigned char *pOutData, int nOutDataOffset, int nBlockMaxSize); + +#endif /* _EXPAND_BLOCK_V1_H */ diff --git a/tools/rasm/lzsa-master/src/expand_block_v2.c b/tools/rasm/lzsa-master/src/expand_block_v2.c new file mode 100644 index 0000000..e024b4c --- /dev/null +++ b/tools/rasm/lzsa-master/src/expand_block_v2.c @@ -0,0 +1,253 @@ +/* + * expand_block_v2.c - LZSA2 block decompressor implementation + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#include +#include +#include "format.h" +#include "expand_block_v2.h" + +#ifdef _MSC_VER +#define FORCE_INLINE __forceinline +#else /* _MSC_VER */ +#define FORCE_INLINE __attribute__((always_inline)) +#endif /* _MSC_VER */ + +static inline FORCE_INLINE unsigned int lzsa_get_nibble_v2(const unsigned char **ppInBlock, const unsigned char *pInBlockEnd, int *nCurNibbles, unsigned char *nibbles, unsigned int *nValue) { + if ((*nCurNibbles ^= 1) != 0) { + const unsigned char *pInBlock = *ppInBlock; + if (pInBlock < pInBlockEnd) { + (*nibbles) = *pInBlock++; + *ppInBlock = pInBlock; + (*nValue) = ((unsigned int)((*nibbles) & 0xf0)) >> 4; + return 0; + } + else { + return -1; + } + } + + (*nValue) = (unsigned int)((*nibbles) & 0x0f); + return 0; +} + +static inline FORCE_INLINE int lzsa_build_len_v2(const unsigned char **ppInBlock, const unsigned char *pInBlockEnd, int *nCurNibbles, unsigned char *nibbles, unsigned int *nLength) { + unsigned int nValue; + + if (!lzsa_get_nibble_v2(ppInBlock, pInBlockEnd, nCurNibbles, nibbles, &nValue)) { + (*nLength) += nValue; + + if (nValue == 15) { + const unsigned char *pInBlock = *ppInBlock; + + if (pInBlock < pInBlockEnd) { + (*nLength) += ((unsigned int)*pInBlock++); + + if ((*nLength) == 257) { + if ((pInBlock + 1) < pInBlockEnd) { + (*nLength) = ((unsigned int)*pInBlock++); + (*nLength) |= (((unsigned int)*pInBlock++) << 8); + } + else { + return -1; + } + } + else if ((*nLength) == 256) { + (*nLength) = 0; + } + } + else { + return -1; + } + + *ppInBlock = pInBlock; + } + + return 0; + } + else { + return -1; + } +} + +/** + * Decompress one LZSA2 data block + * + * @param pInBlock pointer to compressed data + * @param nBlockSize size of compressed data, in bytes + * @param pOutData pointer to output decompression buffer (previously decompressed bytes + room for decompressing this block) + * @param nOutDataOffset starting index of where to store decompressed bytes in output buffer (and size of previously decompressed bytes) + * @param nBlockMaxSize total size of output decompression buffer, in bytes + * + * @return size of decompressed data in bytes, or -1 for error + */ +int lzsa_decompressor_expand_block_v2(const unsigned char *pInBlock, int nBlockSize, unsigned char *pOutData, int nOutDataOffset, int nBlockMaxSize) { + const unsigned char *pInBlockEnd = pInBlock + nBlockSize; + unsigned char *pCurOutData = pOutData + nOutDataOffset; + const unsigned char *pOutDataEnd = pCurOutData + nBlockMaxSize; + const unsigned char *pOutDataFastEnd = pOutDataEnd - 20; + int nCurNibbles = 0; + unsigned char nibbles; + int nMatchOffset = 0; + + while (pInBlock < pInBlockEnd) { + const unsigned char token = *pInBlock++; + unsigned int nLiterals = (unsigned int)((token & 0x18) >> 3); + + if (nLiterals != LITERALS_RUN_LEN_V2 && (pInBlock + 4) <= pInBlockEnd && pCurOutData < pOutDataFastEnd) { + memcpy(pCurOutData, pInBlock, 4); + pInBlock += nLiterals; + pCurOutData += nLiterals; + } + else { + if (nLiterals == LITERALS_RUN_LEN_V2) { + if (lzsa_build_len_v2(&pInBlock, pInBlockEnd, &nCurNibbles, &nibbles, &nLiterals)) + return -1; + } + + if (nLiterals != 0) { + if ((pInBlock + nLiterals) <= pInBlockEnd && + (pCurOutData + nLiterals) <= pOutDataEnd) { + memcpy(pCurOutData, pInBlock, nLiterals); + pInBlock += nLiterals; + pCurOutData += nLiterals; + } + else { + return -1; + } + } + } + + if (pInBlock < pInBlockEnd) { /* The last token in the block does not include match information */ + unsigned char nOffsetMode = token & 0xc0; + unsigned int nValue; + + switch (nOffsetMode) { + case 0x00: + /* 5 bit offset */ + if (lzsa_get_nibble_v2(&pInBlock, pInBlockEnd, &nCurNibbles, &nibbles, &nValue)) + return -1; + nMatchOffset = nValue << 1; + nMatchOffset |= ((token & 0x20) >> 5); + nMatchOffset ^= 0x1e; + nMatchOffset++; + break; + + case 0x40: + /* 9 bit offset */ + nMatchOffset = (unsigned int)(*pInBlock++); + nMatchOffset |= (((unsigned int)(token & 0x20)) << 3); + nMatchOffset ^= 0x0ff; + nMatchOffset++; + break; + + case 0x80: + /* 13 bit offset */ + if (lzsa_get_nibble_v2(&pInBlock, pInBlockEnd, &nCurNibbles, &nibbles, &nValue)) + return -1; + nMatchOffset = (unsigned int)(*pInBlock++); + nMatchOffset |= (nValue << 9); + nMatchOffset |= (((unsigned int)(token & 0x20)) << 3); + nMatchOffset ^= 0x1eff; + nMatchOffset += (512 + 1); + break; + + default: + /* Check if this is a 16 bit offset or a rep-match */ + if ((token & 0x20) == 0) { + /* 16 bit offset */ + nMatchOffset = (((unsigned int)(*pInBlock++)) << 8); + if (pInBlock >= pInBlockEnd) return -1; + nMatchOffset |= (unsigned int)(*pInBlock++); + nMatchOffset ^= 0xffff; + nMatchOffset++; + } + break; + } + + const unsigned char *pSrc = pCurOutData - nMatchOffset; + if (pSrc >= pOutData) { + unsigned int nMatchLen = (unsigned int)(token & 0x07); + if (nMatchLen != MATCH_RUN_LEN_V2 && nMatchOffset >= 8 && pCurOutData < pOutDataFastEnd && (pSrc + 10) <= pOutDataEnd) { + memcpy(pCurOutData, pSrc, 8); + memcpy(pCurOutData + 8, pSrc + 8, 2); + pCurOutData += (MIN_MATCH_SIZE_V2 + nMatchLen); + } + else { + nMatchLen += MIN_MATCH_SIZE_V2; + if (nMatchLen == (MATCH_RUN_LEN_V2 + MIN_MATCH_SIZE_V2)) { + if (lzsa_build_len_v2(&pInBlock, pInBlockEnd, &nCurNibbles, &nibbles, &nMatchLen)) + return -1; + if (nMatchLen == 0) + break; + } + + if ((pSrc + nMatchLen) <= pOutDataEnd) { + if ((pCurOutData + nMatchLen) <= pOutDataEnd) { + /* Do a deterministic, left to right byte copy instead of memcpy() so as to handle overlaps */ + + if (nMatchOffset >= 16 && (pCurOutData + nMatchLen) < (pOutDataFastEnd - 15)) { + const unsigned char *pCopySrc = pSrc; + unsigned char *pCopyDst = pCurOutData; + const unsigned char *pCopyEndDst = pCurOutData + nMatchLen; + + do { + memcpy(pCopyDst, pCopySrc, 16); + pCopySrc += 16; + pCopyDst += 16; + } while (pCopyDst < pCopyEndDst); + + pCurOutData += nMatchLen; + } + else { + while (nMatchLen) { + *pCurOutData++ = *pSrc++; + nMatchLen--; + } + } + } + else { + return -1; + } + } + else { + return -1; + } + } + } + else { + return -1; + } + } + } + + return (int)(pCurOutData - (pOutData + nOutDataOffset)); +} diff --git a/tools/rasm/lzsa-master/src/expand_block_v2.h b/tools/rasm/lzsa-master/src/expand_block_v2.h new file mode 100644 index 0000000..f612f7a --- /dev/null +++ b/tools/rasm/lzsa-master/src/expand_block_v2.h @@ -0,0 +1,49 @@ +/* + * expand_block_v2.h - LZSA2 block decompressor definitions + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#ifndef _EXPAND_BLOCK_V2_H +#define _EXPAND_BLOCK_V2_H + +/** + * Decompress one LZSA2 data block + * + * @param pInBlock pointer to compressed data + * @param nBlockSize size of compressed data, in bytes + * @param pOutData pointer to output decompression buffer (previously decompressed bytes + room for decompressing this block) + * @param nOutDataOffset starting index of where to store decompressed bytes in output buffer (and size of previously decompressed bytes) + * @param nBlockMaxSize total size of output decompression buffer, in bytes + * + * @return size of decompressed data in bytes, or -1 for error + */ +int lzsa_decompressor_expand_block_v2(const unsigned char *pInBlock, int nBlockSize, unsigned char *pOutData, int nOutDataOffset, int nBlockMaxSize); + +#endif /* _EXPAND_BLOCK_V2_H */ diff --git a/tools/rasm/lzsa-master/src/expand_context.c b/tools/rasm/lzsa-master/src/expand_context.c new file mode 100644 index 0000000..b02620d --- /dev/null +++ b/tools/rasm/lzsa-master/src/expand_context.c @@ -0,0 +1,76 @@ +/* + * expand_context.h - decompressor context definitions + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#include +#include +#include "expand_context.h" +#include "expand_block_v1.h" +#include "expand_block_v2.h" +#include "lib.h" + +/** + * Decompress one data block + * + * @param pInBlock pointer to compressed data + * @param nBlockSize size of compressed data, in bytes + * @param pOutData pointer to output decompression buffer (previously decompressed bytes + room for decompressing this block) + * @param nOutDataOffset starting index of where to store decompressed bytes in output buffer (and size of previously decompressed bytes) + * @param nBlockMaxSize total size of output decompression buffer, in bytes + * @param nFormatVersion version of format to use (1-2) + * @param nFlags compression flags (LZSA_FLAG_xxx) + * + * @return size of decompressed data in bytes, or -1 for error + */ +int lzsa_decompressor_expand_block(unsigned char *pInBlock, int nBlockSize, unsigned char *pOutData, int nOutDataOffset, int nBlockMaxSize, const int nFormatVersion, const int nFlags) { + int nDecompressedSize; + + if (nFlags & LZSA_FLAG_RAW_BACKWARD) { + lzsa_reverse_buffer(pInBlock, nBlockSize); + } + + if (nFormatVersion == 1) + nDecompressedSize = lzsa_decompressor_expand_block_v1(pInBlock, nBlockSize, pOutData, nOutDataOffset, nBlockMaxSize); + else if (nFormatVersion == 2) + nDecompressedSize = lzsa_decompressor_expand_block_v2(pInBlock, nBlockSize, pOutData, nOutDataOffset, nBlockMaxSize); + else + nDecompressedSize = -1; + + if (nDecompressedSize != -1 && (nFlags & LZSA_FLAG_RAW_BACKWARD)) { + lzsa_reverse_buffer(pOutData + nOutDataOffset, nDecompressedSize); + } + + if (nFlags & LZSA_FLAG_RAW_BACKWARD) { + lzsa_reverse_buffer(pInBlock, nBlockSize); + } + + return nDecompressedSize; +} diff --git a/tools/rasm/lzsa-master/src/expand_context.h b/tools/rasm/lzsa-master/src/expand_context.h new file mode 100644 index 0000000..698e039 --- /dev/null +++ b/tools/rasm/lzsa-master/src/expand_context.h @@ -0,0 +1,61 @@ +/* + * expand_context.h - decompressor context definitions + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#ifndef _EXPAND_CONTEXT_H +#define _EXPAND_CONTEXT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Decompress one data block + * + * @param pInBlock pointer to compressed data + * @param nBlockSize size of compressed data, in bytes + * @param pOutData pointer to output decompression buffer (previously decompressed bytes + room for decompressing this block) + * @param nOutDataOffset starting index of where to store decompressed bytes in output buffer (and size of previously decompressed bytes) + * @param nBlockMaxSize total size of output decompression buffer, in bytes + * @param nFormatVersion version of format to use (1-2) + * @param nFlags compression flags (LZSA_FLAG_xxx) + * + * @return size of decompressed data in bytes, or -1 for error + */ +int lzsa_decompressor_expand_block(unsigned char *pInBlock, int nBlockSize, unsigned char *pOutData, int nOutDataOffset, int nBlockMaxSize, const int nFormatVersion, const int nFlags); + +#ifdef __cplusplus +} +#endif + +#endif /* _EXPAND_CONTEXT_H */ diff --git a/tools/rasm/lzsa-master/src/expand_inmem.c b/tools/rasm/lzsa-master/src/expand_inmem.c new file mode 100644 index 0000000..050bdbc --- /dev/null +++ b/tools/rasm/lzsa-master/src/expand_inmem.c @@ -0,0 +1,163 @@ +/* + * expand_inmem.c - in-memory decompression implementation + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#include +#include +#include "expand_inmem.h" +#include "lib.h" +#include "frame.h" + +#define BLOCK_SIZE 65536 + +/** + * Get maximum decompressed size of compressed data + * + * @param pFileData compressed data + * @param nFileSize compressed size in bytes + * + * @return maximum decompressed size + */ +size_t lzsa_get_max_decompressed_size_inmem(const unsigned char *pFileData, size_t nFileSize) { + const unsigned char *pCurFileData = pFileData; + const unsigned char *pEndFileData = pCurFileData + nFileSize; + int nFormatVersion = 0; + size_t nMaxDecompressedSize = 0; + const int nHeaderSize = lzsa_get_header_size(); + + /* Check header */ + if ((pCurFileData + nHeaderSize) > pEndFileData || + lzsa_decode_header(pCurFileData, nHeaderSize, &nFormatVersion) != 0) + return -1; + + pCurFileData += nHeaderSize; + + while (pCurFileData < pEndFileData) { + unsigned int nBlockDataSize = 0; + int nIsUncompressed = 0; + const int nFrameSize = lzsa_get_frame_size(); + + /* Decode frame header */ + if ((pCurFileData + nFrameSize) > pEndFileData || + lzsa_decode_frame(pCurFileData, nFrameSize, &nBlockDataSize, &nIsUncompressed) != 0) + return -1; + pCurFileData += nFrameSize; + + if (!nBlockDataSize) + break; + + /* Add one potentially full block to the decompressed size */ + nMaxDecompressedSize += BLOCK_SIZE; + + if ((pCurFileData + nBlockDataSize) > pEndFileData) + return -1; + + pCurFileData += nBlockDataSize; + } + + return nMaxDecompressedSize; +} + +/** + * Decompress data in memory + * + * @param pFileData compressed data + * @param pOutBuffer buffer for decompressed data + * @param nFileSize compressed size in bytes + * @param nMaxOutBufferSize maximum capacity of decompression buffer + * @param nFlags compression flags (LZSA_FLAG_xxx) + * @param pFormatVersion pointer to format version, updated if this function is successful + * + * @return actual decompressed size, or -1 for error + */ +size_t lzsa_decompress_inmem(unsigned char *pFileData, unsigned char *pOutBuffer, size_t nFileSize, size_t nMaxOutBufferSize, const unsigned int nFlags, int *pFormatVersion) { + unsigned char *pCurFileData = pFileData; + const unsigned char *pEndFileData = pCurFileData + nFileSize; + unsigned char *pCurOutBuffer = pOutBuffer; + const unsigned char *pEndOutBuffer = pCurOutBuffer + nMaxOutBufferSize; + int nPreviousBlockSize; + const int nHeaderSize = lzsa_get_header_size(); + + if (nFlags & LZSA_FLAG_RAW_BLOCK) { + return (size_t)lzsa_decompressor_expand_block(pFileData, (int)nFileSize, pOutBuffer, 0, (int)nMaxOutBufferSize, *pFormatVersion, nFlags); + } + + /* Check header */ + if ((pCurFileData + nHeaderSize) > pEndFileData || + lzsa_decode_header(pCurFileData, nHeaderSize, pFormatVersion) != 0) + return -1; + + pCurFileData += nHeaderSize; + nPreviousBlockSize = 0; + + while (pCurFileData < pEndFileData) { + unsigned int nBlockDataSize = 0; + int nIsUncompressed = 0; + const int nFrameSize = lzsa_get_frame_size(); + + /* Decode frame header */ + if ((pCurFileData + nFrameSize) > pEndFileData || + lzsa_decode_frame(pCurFileData, nFrameSize, &nBlockDataSize, &nIsUncompressed) != 0) + return -1; + pCurFileData += nFrameSize; + + if (!nBlockDataSize) + break; + + if (!nIsUncompressed) { + int nDecompressedSize; + + /* Decompress block */ + if ((pCurFileData + nBlockDataSize) > pEndFileData) + return -1; + + nDecompressedSize = lzsa_decompressor_expand_block(pCurFileData, nBlockDataSize, pCurOutBuffer - nPreviousBlockSize, nPreviousBlockSize, (int)(pEndOutBuffer - pCurOutBuffer + nPreviousBlockSize), *pFormatVersion, nFlags); + if (nDecompressedSize < 0) + return -1; + + pCurOutBuffer += nDecompressedSize; + nPreviousBlockSize = nDecompressedSize; + } + else { + /* Copy uncompressed block */ + if ((pCurFileData + nBlockDataSize) > pEndFileData) + return -1; + if ((pCurOutBuffer + nBlockDataSize) > pEndOutBuffer) + return -1; + memcpy(pCurOutBuffer, pCurFileData, nBlockDataSize); + pCurOutBuffer += nBlockDataSize; + } + + pCurFileData += nBlockDataSize; + } + + return (int)(pCurOutBuffer - pOutBuffer); +} diff --git a/tools/rasm/lzsa-master/src/expand_inmem.h b/tools/rasm/lzsa-master/src/expand_inmem.h new file mode 100644 index 0000000..b52ee68 --- /dev/null +++ b/tools/rasm/lzsa-master/src/expand_inmem.h @@ -0,0 +1,70 @@ +/* + * expand_inmem.h - in-memory decompression definitions + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#ifndef _EXPAND_INMEM_H +#define _EXPAND_INMEM_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Get maximum decompressed size of compressed data + * + * @param pFileData compressed data + * @param nFileSize compressed size in bytes + * + * @return maximum decompressed size + */ +size_t lzsa_get_max_decompressed_size_inmem(const unsigned char *pFileData, size_t nFileSize); + +/** + * Decompress data in memory + * + * @param pFileData compressed data + * @param pOutBuffer buffer for decompressed data + * @param nFileSize compressed size in bytes + * @param nMaxOutBufferSize maximum capacity of decompression buffer + * @param nFlags compression flags (LZSA_FLAG_xxx) + * @param pFormatVersion pointer to format version, updated if this function is successful + * + * @return actual decompressed size, or -1 for error + */ +size_t lzsa_decompress_inmem(unsigned char *pFileData, unsigned char *pOutBuffer, size_t nFileSize, size_t nMaxOutBufferSize, const unsigned int nFlags, int *pFormatVersion); + +#ifdef __cplusplus +} +#endif + +#endif /* _EXPAND_INMEM_H */ diff --git a/tools/rasm/lzsa-master/src/expand_streaming.c b/tools/rasm/lzsa-master/src/expand_streaming.c new file mode 100644 index 0000000..b241c68 --- /dev/null +++ b/tools/rasm/lzsa-master/src/expand_streaming.c @@ -0,0 +1,236 @@ +/* + * expand_streaming.c - streaming decompression definitions + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + + +#include +#include +#include "expand_streaming.h" +#include "format.h" +#include "frame.h" +#include "lib.h" + +/*-------------- File API -------------- */ + +/** + * Decompress file + * + * @param pszInFilename name of input(compressed) file to decompress + * @param pszOutFilename name of output(decompressed) file to generate + * @param pszDictionaryFilename name of dictionary file, or NULL for none + * @param nFlags compression flags (LZSA_FLAG_RAW_BLOCK to decompress a raw block, or 0) + * @param nFormatVersion default version of format to use (1-2). This is used when decompressing a raw block, otherwise the version is extracted from the source file + * @param pOriginalSize pointer to returned output(decompressed) size, updated when this function is successful + * @param pCompressedSize pointer to returned input(compressed) size, updated when this function is successful + * + * @return LZSA_OK for success, or an error value from lzsa_status_t + */ +lzsa_status_t lzsa_decompress_file(const char *pszInFilename, const char *pszOutFilename, const char *pszDictionaryFilename, const unsigned int nFlags, int nFormatVersion, + long long *pOriginalSize, long long *pCompressedSize) { + lzsa_stream_t inStream, outStream; + void *pDictionaryData = NULL; + int nDictionaryDataSize = 0; + lzsa_status_t nStatus; + + if (lzsa_filestream_open(&inStream, pszInFilename, "rb") < 0) { + return LZSA_ERROR_SRC; + } + + if (lzsa_filestream_open(&outStream, pszOutFilename, "wb") < 0) { + inStream.close(&inStream); + return LZSA_ERROR_DST; + } + + nStatus = lzsa_dictionary_load(pszDictionaryFilename, &pDictionaryData, &nDictionaryDataSize); + if (nStatus) { + outStream.close(&outStream); + inStream.close(&inStream); + return nStatus; + } + + nStatus = lzsa_decompress_stream(&inStream, &outStream, pDictionaryData, nDictionaryDataSize, nFlags, nFormatVersion, pOriginalSize, pCompressedSize); + + lzsa_dictionary_free(&pDictionaryData); + outStream.close(&outStream); + inStream.close(&inStream); + + return nStatus; +} + +/*-------------- Streaming API -------------- */ + +/** + * Decompress stream + * + * @param pInStream input(compressed) stream to decompress + * @param pOutStream output(decompressed) stream to write to + * @param pDictionaryData dictionary contents, or NULL for none + * @param nDictionaryDataSize size of dictionary contents, or 0 + * @param nFlags compression flags (LZSA_FLAG_RAW_BLOCK to decompress a raw block, or 0) + * @param nFormatVersion default version of format to use (1-2). This is used when decompressing a raw block, otherwise the version is extracted from the source file + * @param pOriginalSize pointer to returned output(decompressed) size, updated when this function is successful + * @param pCompressedSize pointer to returned input(compressed) size, updated when this function is successful + * + * @return LZSA_OK for success, or an error value from lzsa_status_t + */ +lzsa_status_t lzsa_decompress_stream(lzsa_stream_t *pInStream, lzsa_stream_t *pOutStream, const void *pDictionaryData, int nDictionaryDataSize, const unsigned int nFlags, int nFormatVersion, + long long *pOriginalSize, long long *pCompressedSize) { + long long nOriginalSize = 0LL, nCompressedSize = 0LL; + unsigned char cFrameData[16]; + unsigned char *pInBlock; + unsigned char *pOutData; + + if ((nFlags & LZSA_FLAG_RAW_BLOCK) == 0) { + const int nHeaderSize = lzsa_get_header_size(); + + memset(cFrameData, 0, 16); + if (pInStream->read(pInStream, cFrameData, nHeaderSize) != nHeaderSize) { + return LZSA_ERROR_SRC; + } + + if (lzsa_decode_header(cFrameData, nHeaderSize, &nFormatVersion) < 0) { + return LZSA_ERROR_FORMAT; + } + + nCompressedSize += (long long)nHeaderSize; + } + + pInBlock = (unsigned char*)malloc(BLOCK_SIZE); + if (!pInBlock) { + return LZSA_ERROR_MEMORY; + } + + pOutData = (unsigned char*)malloc(BLOCK_SIZE * 2); + if (!pOutData) { + free(pInBlock); + pInBlock = NULL; + + return LZSA_ERROR_MEMORY; + } + + int nDecompressionError = 0; + int nPrevDecompressedSize = 0; + int nNumBlocks = 0; + + while (!pInStream->eof(pInStream) && !nDecompressionError) { + unsigned int nBlockSize = 0; + int nIsUncompressed = 0; + + if (nPrevDecompressedSize != 0) { + memcpy(pOutData + BLOCK_SIZE - nPrevDecompressedSize, pOutData + BLOCK_SIZE, nPrevDecompressedSize); + } + else if (nDictionaryDataSize && pDictionaryData) { + nPrevDecompressedSize = nDictionaryDataSize; + memcpy(pOutData + BLOCK_SIZE - nPrevDecompressedSize, pDictionaryData, nPrevDecompressedSize); + } + + if ((nFlags & LZSA_FLAG_RAW_BLOCK) == 0) { + const int nFrameSize = lzsa_get_frame_size(); + + memset(cFrameData, 0, 16); + if (pInStream->read(pInStream, cFrameData, nFrameSize) == nFrameSize) { + if (lzsa_decode_frame(cFrameData, nFrameSize, &nBlockSize, &nIsUncompressed) < 0) { + nDecompressionError = LZSA_ERROR_FORMAT; + nBlockSize = 0; + } + + nCompressedSize += (long long)nFrameSize; + } + else { + nDecompressionError = LZSA_ERROR_SRC; + nBlockSize = 0; + } + } + else { + if (!nNumBlocks) + nBlockSize = BLOCK_SIZE; + else + nBlockSize = 0; + } + + if (nBlockSize != 0) { + int nDecompressedSize = 0; + + if ((int)nBlockSize > BLOCK_SIZE) { + nDecompressionError = LZSA_ERROR_FORMAT; + break; + } + size_t nReadBytes = pInStream->read(pInStream, pInBlock, nBlockSize); + if (nFlags & LZSA_FLAG_RAW_BLOCK) { + nBlockSize = (unsigned int)nReadBytes; + } + + if (nReadBytes == nBlockSize) { + nCompressedSize += (long long)nReadBytes; + + if (nIsUncompressed) { + memcpy(pOutData + BLOCK_SIZE, pInBlock, nBlockSize); + nDecompressedSize = nBlockSize; + } + else { + nDecompressedSize = lzsa_decompressor_expand_block(pInBlock, nBlockSize, pOutData, BLOCK_SIZE, BLOCK_SIZE, nFormatVersion, nFlags); + if (nDecompressedSize < 0) { + nDecompressionError = LZSA_ERROR_DECOMPRESSION; + break; + } + } + + if (nDecompressedSize != 0) { + nOriginalSize += (long long)nDecompressedSize; + + if (pOutStream->write(pOutStream, pOutData + BLOCK_SIZE, nDecompressedSize) != nDecompressedSize) + nDecompressionError = LZSA_ERROR_DST; + nPrevDecompressedSize = nDecompressedSize; + nDecompressedSize = 0; + } + } + else { + break; + } + + nNumBlocks++; + } + else { + break; + } + } + + free(pOutData); + pOutData = NULL; + + free(pInBlock); + pInBlock = NULL; + + *pOriginalSize = nOriginalSize; + *pCompressedSize = nCompressedSize; + return nDecompressionError; +} + diff --git a/tools/rasm/lzsa-master/src/expand_streaming.h b/tools/rasm/lzsa-master/src/expand_streaming.h new file mode 100644 index 0000000..30dd88d --- /dev/null +++ b/tools/rasm/lzsa-master/src/expand_streaming.h @@ -0,0 +1,86 @@ +/* + * expand_streaming.h - streaming decompression definitions + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#ifndef _EXPAND_STREAMING_H +#define _EXPAND_STREAMING_H + +#include "stream.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declaration */ +typedef enum _lzsa_status_t lzsa_status_t; + +/*-------------- File API -------------- */ + +/** + * Decompress file + * + * @param pszInFilename name of input(compressed) file to decompress + * @param pszOutFilename name of output(decompressed) file to generate + * @param pszDictionaryFilename name of dictionary file, or NULL for none + * @param nFlags compression flags (LZSA_FLAG_RAW_BLOCK to decompress a raw block, or 0) + * @param nFormatVersion default version of format to use (1-2). This is used when decompressing a raw block, otherwise the version is extracted from the source file + * @param pOriginalSize pointer to returned output(decompressed) size, updated when this function is successful + * @param pCompressedSize pointer to returned input(compressed) size, updated when this function is successful + * + * @return LZSA_OK for success, or an error value from lzsa_status_t + */ +lzsa_status_t lzsa_decompress_file(const char *pszInFilename, const char *pszOutFilename, const char *pszDictionaryFilename, const unsigned int nFlags, int nFormatVersion, + long long *pOriginalSize, long long *pCompressedSize); + +/*-------------- Streaming API -------------- */ + +/** + * Decompress stream + * + * @param pInStream input(compressed) stream to decompress + * @param pOutStream output(decompressed) stream to write to + * @param pDictionaryData dictionary contents, or NULL for none + * @param nDictionaryDataSize size of dictionary contents, or 0 + * @param nFlags compression flags (LZSA_FLAG_RAW_BLOCK to decompress a raw block, or 0) + * @param nFormatVersion default version of format to use (1-2). This is used when decompressing a raw block, otherwise the version is extracted from the source file + * @param pOriginalSize pointer to returned output(decompressed) size, updated when this function is successful + * @param pCompressedSize pointer to returned input(compressed) size, updated when this function is successful + * + * @return LZSA_OK for success, or an error value from lzsa_status_t + */ +lzsa_status_t lzsa_decompress_stream(lzsa_stream_t *pInStream, lzsa_stream_t *pOutStream, const void *pDictionaryData, int nDictionaryDataSize, const unsigned int nFlags, int nFormatVersion, + long long *pOriginalSize, long long *pCompressedSize); + +#ifdef __cplusplus +} +#endif + +#endif /* _EXPAND_STREAMING_H */ diff --git a/tools/rasm/lzsa-master/src/format.h b/tools/rasm/lzsa-master/src/format.h new file mode 100755 index 0000000..ace4f15 --- /dev/null +++ b/tools/rasm/lzsa-master/src/format.h @@ -0,0 +1,51 @@ +/* + * format.h - byte stream format definitions + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#ifndef _FORMAT_H +#define _FORMAT_H + +#define MIN_OFFSET 1 +#define MAX_OFFSET 0xffff + +#define MAX_VARLEN 0xffff + +#define BLOCK_SIZE 65536 + +#define MIN_MATCH_SIZE_V1 3 +#define LITERALS_RUN_LEN_V1 7 +#define MATCH_RUN_LEN_V1 15 + +#define MIN_MATCH_SIZE_V2 2 +#define LITERALS_RUN_LEN_V2 3 +#define MATCH_RUN_LEN_V2 7 + +#endif /* _FORMAT_H */ diff --git a/tools/rasm/lzsa-master/src/frame.c b/tools/rasm/lzsa-master/src/frame.c new file mode 100644 index 0000000..f1d6be2 --- /dev/null +++ b/tools/rasm/lzsa-master/src/frame.c @@ -0,0 +1,189 @@ +/* + * frame.c - frame implementation + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#include +#include +#include "frame.h" + +#define LZSA_ID_0 0x7b +#define LZSA_ID_1 0x9e + +/** + * Get compressed file header size + * + * @return file header size + */ +int lzsa_get_header_size(void) { + return 3; +} + +/** + * Get compressed frame header size + * + * @return frame header size + */ +int lzsa_get_frame_size(void) { + return 3; +} + +/** + * Encode file header + * + * @param pFrameData encoding buffer + * @param nMaxFrameDataSize max encoding buffer size, in bytes + * + * @return number of encoded bytes, or -1 for failure + */ +int lzsa_encode_header(unsigned char *pFrameData, const int nMaxFrameDataSize, int nFormatVersion) { + if (nMaxFrameDataSize >= 3 && (nFormatVersion == 1 || nFormatVersion == 2)) { + pFrameData[0] = LZSA_ID_0; /* Magic number */ + pFrameData[1] = LZSA_ID_1; + pFrameData[2] = (nFormatVersion == 2) ? 0x20 : 0; /* Format version 1 */ + + return 3; + } + else { + return -1; + } +} + +/** + * Encode compressed block frame header + * + * @param pFrameData encoding buffer + * @param nMaxFrameDataSize max encoding buffer size, in bytes + * @param nBlockDataSize compressed block's data size, in bytes + * + * @return number of encoded bytes, or -1 for failure + */ +int lzsa_encode_compressed_block_frame(unsigned char *pFrameData, const int nMaxFrameDataSize, const int nBlockDataSize) { + if (nMaxFrameDataSize >= 3 && nBlockDataSize <= 0x7fffff) { + pFrameData[0] = nBlockDataSize & 0xff; + pFrameData[1] = (nBlockDataSize >> 8) & 0xff; + pFrameData[2] = (nBlockDataSize >> 16) & 0x7f; + + return 3; + } + else { + return -1; + } +} + +/** + * Encode uncompressed block frame header + * + * @param pFrameData encoding buffer + * @param nMaxFrameDataSize max encoding buffer size, in bytes + * @param nBlockDataSize uncompressed block's data size, in bytes + * + * @return number of encoded bytes, or -1 for failure + */ +int lzsa_encode_uncompressed_block_frame(unsigned char *pFrameData, const int nMaxFrameDataSize, const int nBlockDataSize) { + if (nMaxFrameDataSize >= 3 && nBlockDataSize <= 0x7fffff) { + pFrameData[0] = nBlockDataSize & 0xff; + pFrameData[1] = (nBlockDataSize >> 8) & 0xff; + pFrameData[2] = ((nBlockDataSize >> 16) & 0x7f) | 0x80; /* Uncompressed block */ + + return 3; + } + else { + return -1; + } +} + +/** + * Encode terminal frame header + * + * @param pFrameData encoding buffer + * @param nMaxFrameDataSize max encoding buffer size, in bytes + * + * @return number of encoded bytes, or -1 for failure + */ +int lzsa_encode_footer_frame(unsigned char *pFrameData, const int nMaxFrameDataSize) { + if (nMaxFrameDataSize >= 3) { + pFrameData[0] = 0x00; /* EOD frame */ + pFrameData[1] = 0x00; + pFrameData[2] = 0x00; + + return 3; + } + else { + return -1; + } +} + +/** + * Decode file header + * + * @param pFrameData data bytes + * @param nFrameDataSize number of bytes to decode + * + * @return 0 for success, or -1 for failure + */ +int lzsa_decode_header(const unsigned char *pFrameData, const int nFrameDataSize, int *nFormatVersion) { + if (nFrameDataSize != 3 || + pFrameData[0] != LZSA_ID_0 || + pFrameData[1] != LZSA_ID_1 || + (pFrameData[2] & 0x1f) != 0 || + ((pFrameData[2] & 0xe0) != 0x00 && (pFrameData[2] & 0xe0) != 0x20)) { + return -1; + } + else { + *nFormatVersion = (pFrameData[2] & 0xe0) ? 2 : 1; + return 0; + } +} + +/** + * Decode frame header + * + * @param pFrameData data bytes + * @param nFrameDataSize number of bytes to decode + * @param nBlockSize pointer to block size, updated if this function succeeds (set to 0 if this is the terminal frame) + * @param nIsUncompressed pointer to compressed block flag, updated if this function succeeds + * + * @return 0 for success, or -1 for failure + */ +int lzsa_decode_frame(const unsigned char *pFrameData, const int nFrameDataSize, unsigned int *nBlockSize, int *nIsUncompressed) { + if (nFrameDataSize == 3) { + *nBlockSize = ((unsigned int)pFrameData[0]) | + (((unsigned int)pFrameData[1]) << 8) | + (((unsigned int)pFrameData[2]) << 16); + + *nIsUncompressed = ((*nBlockSize & 0x800000) != 0) ? 1 : 0; + *nBlockSize &= 0x7fffff; + return 0; + } + else { + return -1; + } +} diff --git a/tools/rasm/lzsa-master/src/frame.h b/tools/rasm/lzsa-master/src/frame.h new file mode 100644 index 0000000..7b5db99 --- /dev/null +++ b/tools/rasm/lzsa-master/src/frame.h @@ -0,0 +1,122 @@ +/* + * frame.h - frame definitions + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#ifndef _FRAME_H +#define _FRAME_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Get compressed file header size + * + * @return file header size + */ +int lzsa_get_header_size(void); + +/** + * Get compressed frame header size + * + * @return frame header size + */ +int lzsa_get_frame_size(void); + +/** + * Encode file header + * + * @param pFrameData encoding buffer + * @param nMaxFrameDataSize max encoding buffer size, in bytes + * + * @return number of encoded bytes, or -1 for failure + */ +int lzsa_encode_header(unsigned char *pFrameData, const int nMaxFrameDataSize, int nFormatVersion); + +/** + * Encode compressed block frame header + * + * @param pFrameData encoding buffer + * @param nMaxFrameDataSize max encoding buffer size, in bytes + * @param nBlockDataSize compressed block's data size, in bytes + * + * @return number of encoded bytes, or -1 for failure + */ +int lzsa_encode_compressed_block_frame(unsigned char *pFrameData, const int nMaxFrameDataSize, const int nBlockDataSize); + +/** + * Encode uncompressed block frame header + * + * @param pFrameData encoding buffer + * @param nMaxFrameDataSize max encoding buffer size, in bytes + * @param nBlockDataSize uncompressed block's data size, in bytes + * + * @return number of encoded bytes, or -1 for failure + */ +int lzsa_encode_uncompressed_block_frame(unsigned char *pFrameData, const int nMaxFrameDataSize, const int nBlockDataSize); + +/** + * Encode terminal frame header + * + * @param pFrameData encoding buffer + * @param nMaxFrameDataSize max encoding buffer size, in bytes + * + * @return number of encoded bytes, or -1 for failure + */ +int lzsa_encode_footer_frame(unsigned char *pFrameData, const int nMaxFrameDataSize); + +/** + * Decode file header + * + * @param pFrameData data bytes + * @param nFrameDataSize number of bytes to decode + * + * @return 0 for success, or -1 for failure + */ +int lzsa_decode_header(const unsigned char *pFrameData, const int nFrameDataSize, int *nFormatVersion); + +/** + * Decode frame header + * + * @param pFrameData data bytes + * @param nFrameDataSize number of bytes to decode + * @param nBlockSize pointer to block size, updated if this function succeeds (set to 0 if this is the terminal frame) + * @param nIsUncompressed pointer to compressed block flag, updated if this function succeeds + * + * @return 0 for success, or -1 for failure + */ +int lzsa_decode_frame(const unsigned char *pFrameData, const int nFrameDataSize, unsigned int *nBlockSize, int *nIsUncompressed); + +#ifdef __cplusplus +} +#endif + +#endif /* _FRAME_H */ diff --git a/tools/rasm/lzsa-master/src/lib.h b/tools/rasm/lzsa-master/src/lib.h new file mode 100755 index 0000000..2520b13 --- /dev/null +++ b/tools/rasm/lzsa-master/src/lib.h @@ -0,0 +1,95 @@ +/* + * lib.h - LZSA library definitions + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#ifndef _LIB_H +#define _LIB_H + +#include "stream.h" +#include "dictionary.h" +#include "frame.h" +#include "format.h" +#include "shrink_context.h" +#include "shrink_streaming.h" +#include "shrink_inmem.h" +#include "expand_context.h" +#include "expand_streaming.h" +#include "expand_inmem.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** High level status for compression and decompression */ +typedef enum _lzsa_status_t { + LZSA_OK = 0, /**< Success */ + LZSA_ERROR_SRC, /**< Error reading input */ + LZSA_ERROR_DST, /**< Error reading output */ + LZSA_ERROR_DICTIONARY, /**< Error reading dictionary */ + LZSA_ERROR_MEMORY, /**< Out of memory */ + + /* Compression-specific status codes */ + LZSA_ERROR_COMPRESSION, /**< Internal compression error */ + LZSA_ERROR_RAW_TOOLARGE, /**< Input is too large to be compressed to a raw block */ + LZSA_ERROR_RAW_UNCOMPRESSED, /**< Input is incompressible and raw blocks don't support uncompressed data */ + + /* Decompression-specific status codes */ + LZSA_ERROR_FORMAT, /**< Invalid input format or magic number when decompressing */ + LZSA_ERROR_DECOMPRESSION /**< Internal decompression error */ +} lzsa_status_t; + +/* Compression flags */ +#define LZSA_FLAG_FAVOR_RATIO (1<<0) /**< 1 to compress with the best ratio, 0 to trade some compression ratio for extra decompression speed */ +#define LZSA_FLAG_RAW_BLOCK (1<<1) /**< 1 to emit raw block */ +#define LZSA_FLAG_RAW_BACKWARD (1<<2) /**< 1 to compress or decompress raw block backward */ + +/** + * Reverse bytes in the specified buffer + * + * @param pBuffer pointer to buffer whose contents are to be reversed + * @param nBufferSize size of buffer in bytes + */ +static inline void lzsa_reverse_buffer(unsigned char *pBuffer, const int nBufferSize) { + int nMidPoint = nBufferSize / 2; + int i, j; + + for (i = 0, j = nBufferSize - 1; i < nMidPoint; i++, j--) { + unsigned char c = pBuffer[i]; + pBuffer[i] = pBuffer[j]; + pBuffer[j] = c; + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* _LIB_H */ diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/.gitignore b/tools/rasm/lzsa-master/src/libdivsufsort/.gitignore new file mode 100644 index 0000000..a0a0666 --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/.gitignore @@ -0,0 +1,32 @@ +# Object files +*.o +*.ko +*.obj +*.elf + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# CMake files/directories +build/ diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/CHANGELOG.md b/tools/rasm/lzsa-master/src/libdivsufsort/CHANGELOG.md new file mode 100644 index 0000000..fe9d004 --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/CHANGELOG.md @@ -0,0 +1,21 @@ +# libdivsufsort Change Log + +See full changelog at: https://github.com/y-256/libdivsufsort/commits + +## [2.0.1] - 2010-11-11 +### Fixed +* Wrong variable used in `divbwt` function +* Enclose some string variables with double quotation marks in include/CMakeLists.txt +* Fix typo in include/CMakeLists.txt + +## 2.0.0 - 2008-08-23 +### Changed +* Switch the build system to [CMake](http://www.cmake.org/) +* Improve the performance of the suffix-sorting algorithm + +### Added +* OpenMP support +* 64-bit version of divsufsort + +[Unreleased]: https://github.com/y-256/libdivsufsort/compare/2.0.1...HEAD +[2.0.1]: https://github.com/y-256/libdivsufsort/compare/2.0.0...2.0.1 diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/CMakeLists.txt b/tools/rasm/lzsa-master/src/libdivsufsort/CMakeLists.txt new file mode 100644 index 0000000..7859943 --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/CMakeLists.txt @@ -0,0 +1,99 @@ +### cmake file for building libdivsufsort Package ### +cmake_minimum_required(VERSION 2.4.4) +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules") +include(AppendCompilerFlags) + +## Project information ## +project(libdivsufsort C) +set(PROJECT_VENDOR "Yuta Mori") +set(PROJECT_CONTACT "yuta.256@gmail.com") +set(PROJECT_URL "https://github.com/y-256/libdivsufsort") +set(PROJECT_DESCRIPTION "A lightweight suffix sorting library") +include(VERSION.cmake) + +## CPack configuration ## +set(CPACK_GENERATOR "TGZ;TBZ2;ZIP") +set(CPACK_SOURCE_GENERATOR "TGZ;TBZ2;ZIP") +include(ProjectCPack) + +## Project options ## +option(BUILD_SHARED_LIBS "Set to OFF to build static libraries" ON) +option(BUILD_EXAMPLES "Build examples" ON) +option(BUILD_DIVSUFSORT64 "Build libdivsufsort64" OFF) +option(USE_OPENMP "Use OpenMP for parallelization" OFF) +option(WITH_LFS "Enable Large File Support" ON) + +## Installation directories ## +set(LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32 or 64)") + +set(CMAKE_INSTALL_RUNTIMEDIR "" CACHE PATH "Specify the output directory for dll runtimes (default is bin)") +if(NOT CMAKE_INSTALL_RUNTIMEDIR) + set(CMAKE_INSTALL_RUNTIMEDIR "${CMAKE_INSTALL_PREFIX}/bin") +endif(NOT CMAKE_INSTALL_RUNTIMEDIR) + +set(CMAKE_INSTALL_LIBDIR "" CACHE PATH "Specify the output directory for libraries (default is lib)") +if(NOT CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}") +endif(NOT CMAKE_INSTALL_LIBDIR) + +set(CMAKE_INSTALL_INCLUDEDIR "" CACHE PATH "Specify the output directory for header files (default is include)") +if(NOT CMAKE_INSTALL_INCLUDEDIR) + set(CMAKE_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_PREFIX}/include") +endif(NOT CMAKE_INSTALL_INCLUDEDIR) + +set(CMAKE_INSTALL_PKGCONFIGDIR "" CACHE PATH "Specify the output directory for pkgconfig files (default is lib/pkgconfig)") +if(NOT CMAKE_INSTALL_PKGCONFIGDIR) + set(CMAKE_INSTALL_PKGCONFIGDIR "${CMAKE_INSTALL_LIBDIR}/pkgconfig") +endif(NOT CMAKE_INSTALL_PKGCONFIGDIR) + +## Build type ## +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release") +elseif(CMAKE_BUILD_TYPE STREQUAL "Debug") + set(CMAKE_VERBOSE_MAKEFILE ON) +endif(NOT CMAKE_BUILD_TYPE) + +## Compiler options ## +if(MSVC) + append_c_compiler_flags("/W4" "VC" CMAKE_C_FLAGS) + append_c_compiler_flags("/Oi;/Ot;/Ox;/Oy" "VC" CMAKE_C_FLAGS_RELEASE) + if(USE_OPENMP) + append_c_compiler_flags("/openmp" "VC" CMAKE_C_FLAGS) + endif(USE_OPENMP) +elseif(BORLAND) + append_c_compiler_flags("-w" "BCC" CMAKE_C_FLAGS) + append_c_compiler_flags("-Oi;-Og;-Os;-Ov;-Ox" "BCC" CMAKE_C_FLAGS_RELEASE) +else(MSVC) + if(CMAKE_COMPILER_IS_GNUCC) + append_c_compiler_flags("-Wall" "GCC" CMAKE_C_FLAGS) + append_c_compiler_flags("-fomit-frame-pointer" "GCC" CMAKE_C_FLAGS_RELEASE) + if(USE_OPENMP) + append_c_compiler_flags("-fopenmp" "GCC" CMAKE_C_FLAGS) + endif(USE_OPENMP) + else(CMAKE_COMPILER_IS_GNUCC) + append_c_compiler_flags("-Wall" "UNKNOWN" CMAKE_C_FLAGS) + append_c_compiler_flags("-fomit-frame-pointer" "UNKNOWN" CMAKE_C_FLAGS_RELEASE) + if(USE_OPENMP) + append_c_compiler_flags("-fopenmp;-openmp;-omp" "UNKNOWN" CMAKE_C_FLAGS) + endif(USE_OPENMP) + endif(CMAKE_COMPILER_IS_GNUCC) +endif(MSVC) + +## Add definitions ## +add_definitions(-DHAVE_CONFIG_H=1 -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS) + +## Add subdirectories ## +add_subdirectory(pkgconfig) +add_subdirectory(include) +add_subdirectory(lib) +if(BUILD_EXAMPLES) + add_subdirectory(examples) +endif(BUILD_EXAMPLES) + +## Add 'uninstall' target ## +CONFIGURE_FILE( + "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/CMakeModules/cmake_uninstall.cmake" + IMMEDIATE @ONLY) +ADD_CUSTOM_TARGET(uninstall + "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/CMakeModules/cmake_uninstall.cmake") diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/CMakeModules/AppendCompilerFlags.cmake b/tools/rasm/lzsa-master/src/libdivsufsort/CMakeModules/AppendCompilerFlags.cmake new file mode 100644 index 0000000..58d3f99 --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/CMakeModules/AppendCompilerFlags.cmake @@ -0,0 +1,38 @@ +include(CheckCSourceCompiles) +include(CheckCXXSourceCompiles) + +macro(append_c_compiler_flags _flags _name _result) + set(SAFE_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) + string(REGEX REPLACE "[-+/ ]" "_" cname "${_name}") + string(TOUPPER "${cname}" cname) + foreach(flag ${_flags}) + string(REGEX REPLACE "^[-+/ ]+(.*)[-+/ ]*$" "\\1" flagname "${flag}") + string(REGEX REPLACE "[-+/ ]" "_" flagname "${flagname}") + string(TOUPPER "${flagname}" flagname) + set(have_flag "HAVE_${cname}_${flagname}") + set(CMAKE_REQUIRED_FLAGS "${flag}") + check_c_source_compiles("int main() { return 0; }" ${have_flag}) + if(${have_flag}) + set(${_result} "${${_result}} ${flag}") + endif(${have_flag}) + endforeach(flag) + set(CMAKE_REQUIRED_FLAGS ${SAFE_CMAKE_REQUIRED_FLAGS}) +endmacro(append_c_compiler_flags) + +macro(append_cxx_compiler_flags _flags _name _result) + set(SAFE_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) + string(REGEX REPLACE "[-+/ ]" "_" cname "${_name}") + string(TOUPPER "${cname}" cname) + foreach(flag ${_flags}) + string(REGEX REPLACE "^[-+/ ]+(.*)[-+/ ]*$" "\\1" flagname "${flag}") + string(REGEX REPLACE "[-+/ ]" "_" flagname "${flagname}") + string(TOUPPER "${flagname}" flagname) + set(have_flag "HAVE_${cname}_${flagname}") + set(CMAKE_REQUIRED_FLAGS "${flag}") + check_cxx_source_compiles("int main() { return 0; }" ${have_flag}) + if(${have_flag}) + set(${_result} "${${_result}} ${flag}") + endif(${have_flag}) + endforeach(flag) + set(CMAKE_REQUIRED_FLAGS ${SAFE_CMAKE_REQUIRED_FLAGS}) +endmacro(append_cxx_compiler_flags) diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/CMakeModules/CheckFunctionKeywords.cmake b/tools/rasm/lzsa-master/src/libdivsufsort/CMakeModules/CheckFunctionKeywords.cmake new file mode 100644 index 0000000..44601fd --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/CMakeModules/CheckFunctionKeywords.cmake @@ -0,0 +1,15 @@ +include(CheckCSourceCompiles) + +macro(check_function_keywords _wordlist) + set(${_result} "") + foreach(flag ${_wordlist}) + string(REGEX REPLACE "[-+/ ()]" "_" flagname "${flag}") + string(TOUPPER "${flagname}" flagname) + set(have_flag "HAVE_${flagname}") + check_c_source_compiles("${flag} void func(); void func() { } int main() { func(); return 0; }" ${have_flag}) + if(${have_flag} AND NOT ${_result}) + set(${_result} "${flag}") +# break() + endif(${have_flag} AND NOT ${_result}) + endforeach(flag) +endmacro(check_function_keywords) diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/CMakeModules/CheckLFS.cmake b/tools/rasm/lzsa-master/src/libdivsufsort/CMakeModules/CheckLFS.cmake new file mode 100644 index 0000000..e2b0099 --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/CMakeModules/CheckLFS.cmake @@ -0,0 +1,109 @@ +## Checks for large file support ## +include(CheckIncludeFile) +include(CheckSymbolExists) +include(CheckTypeSize) + +macro(check_lfs _isenable) + set(LFS_OFF_T "") + set(LFS_FOPEN "") + set(LFS_FSEEK "") + set(LFS_FTELL "") + set(LFS_PRID "") + + if(${_isenable}) + set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}") + set(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} + -D_LARGEFILE_SOURCE -D_LARGE_FILES -D_FILE_OFFSET_BITS=64 + -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS) + + check_include_file("sys/types.h" HAVE_SYS_TYPES_H) + check_include_file("inttypes.h" HAVE_INTTYPES_H) + check_include_file("stddef.h" HAVE_STDDEF_H) + check_include_file("stdint.h" HAVE_STDINT_H) + + # LFS type1: 8 <= sizeof(off_t), fseeko, ftello + check_type_size("off_t" SIZEOF_OFF_T) + if(SIZEOF_OFF_T GREATER 7) + check_symbol_exists("fseeko" "stdio.h" HAVE_FSEEKO) + check_symbol_exists("ftello" "stdio.h" HAVE_FTELLO) + if(HAVE_FSEEKO AND HAVE_FTELLO) + set(LFS_OFF_T "off_t") + set(LFS_FOPEN "fopen") + set(LFS_FSEEK "fseeko") + set(LFS_FTELL "ftello") + check_symbol_exists("PRIdMAX" "inttypes.h" HAVE_PRIDMAX) + if(HAVE_PRIDMAX) + set(LFS_PRID "PRIdMAX") + else(HAVE_PRIDMAX) + check_type_size("long" SIZEOF_LONG) + check_type_size("int" SIZEOF_INT) + if(SIZEOF_OFF_T GREATER SIZEOF_LONG) + set(LFS_PRID "\"lld\"") + elseif(SIZEOF_LONG GREATER SIZEOF_INT) + set(LFS_PRID "\"ld\"") + else(SIZEOF_OFF_T GREATER SIZEOF_LONG) + set(LFS_PRID "\"d\"") + endif(SIZEOF_OFF_T GREATER SIZEOF_LONG) + endif(HAVE_PRIDMAX) + endif(HAVE_FSEEKO AND HAVE_FTELLO) + endif(SIZEOF_OFF_T GREATER 7) + + # LFS type2: 8 <= sizeof(off64_t), fopen64, fseeko64, ftello64 + if(NOT LFS_OFF_T) + check_type_size("off64_t" SIZEOF_OFF64_T) + if(SIZEOF_OFF64_T GREATER 7) + check_symbol_exists("fopen64" "stdio.h" HAVE_FOPEN64) + check_symbol_exists("fseeko64" "stdio.h" HAVE_FSEEKO64) + check_symbol_exists("ftello64" "stdio.h" HAVE_FTELLO64) + if(HAVE_FOPEN64 AND HAVE_FSEEKO64 AND HAVE_FTELLO64) + set(LFS_OFF_T "off64_t") + set(LFS_FOPEN "fopen64") + set(LFS_FSEEK "fseeko64") + set(LFS_FTELL "ftello64") + check_symbol_exists("PRIdMAX" "inttypes.h" HAVE_PRIDMAX) + if(HAVE_PRIDMAX) + set(LFS_PRID "PRIdMAX") + else(HAVE_PRIDMAX) + check_type_size("long" SIZEOF_LONG) + check_type_size("int" SIZEOF_INT) + if(SIZEOF_OFF64_T GREATER SIZEOF_LONG) + set(LFS_PRID "\"lld\"") + elseif(SIZEOF_LONG GREATER SIZEOF_INT) + set(LFS_PRID "\"ld\"") + else(SIZEOF_OFF64_T GREATER SIZEOF_LONG) + set(LFS_PRID "\"d\"") + endif(SIZEOF_OFF64_T GREATER SIZEOF_LONG) + endif(HAVE_PRIDMAX) + endif(HAVE_FOPEN64 AND HAVE_FSEEKO64 AND HAVE_FTELLO64) + endif(SIZEOF_OFF64_T GREATER 7) + endif(NOT LFS_OFF_T) + + # LFS type3: 8 <= sizeof(__int64), _fseeki64, _ftelli64 + if(NOT LFS_OFF_T) + check_type_size("__int64" SIZEOF___INT64) + if(SIZEOF___INT64 GREATER 7) + check_symbol_exists("_fseeki64" "stdio.h" HAVE__FSEEKI64) + check_symbol_exists("_ftelli64" "stdio.h" HAVE__FTELLI64) + if(HAVE__FSEEKI64 AND HAVE__FTELLI64) + set(LFS_OFF_T "__int64") + set(LFS_FOPEN "fopen") + set(LFS_FSEEK "_fseeki64") + set(LFS_FTELL "_ftelli64") + set(LFS_PRID "\"I64d\"") + endif(HAVE__FSEEKI64 AND HAVE__FTELLI64) + endif(SIZEOF___INT64 GREATER 7) + endif(NOT LFS_OFF_T) + + set(CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}") + endif(${_isenable}) + + if(NOT LFS_OFF_T) + ## not found + set(LFS_OFF_T "long") + set(LFS_FOPEN "fopen") + set(LFS_FSEEK "fseek") + set(LFS_FTELL "ftell") + set(LFS_PRID "\"ld\"") + endif(NOT LFS_OFF_T) + +endmacro(check_lfs) diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/CMakeModules/ProjectCPack.cmake b/tools/rasm/lzsa-master/src/libdivsufsort/CMakeModules/ProjectCPack.cmake new file mode 100644 index 0000000..7c105f9 --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/CMakeModules/ProjectCPack.cmake @@ -0,0 +1,38 @@ +# If the cmake version includes cpack, use it +IF(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") + SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PROJECT_DESCRIPTION}") + SET(CPACK_PACKAGE_VENDOR "${PROJECT_VENDOR}") + SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md") + SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") + SET(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}") + SET(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}") + SET(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}") +# SET(CPACK_PACKAGE_INSTALL_DIRECTORY "${PROJECT_NAME} ${PROJECT_VERSION}") + SET(CPACK_SOURCE_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION_FULL}") + + IF(NOT DEFINED CPACK_SYSTEM_NAME) + SET(CPACK_SYSTEM_NAME "${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}") + ENDIF(NOT DEFINED CPACK_SYSTEM_NAME) + + IF(${CPACK_SYSTEM_NAME} MATCHES Windows) + IF(CMAKE_CL_64) + SET(CPACK_SYSTEM_NAME win64-${CMAKE_SYSTEM_PROCESSOR}) + ELSE(CMAKE_CL_64) + SET(CPACK_SYSTEM_NAME win32-${CMAKE_SYSTEM_PROCESSOR}) + ENDIF(CMAKE_CL_64) + ENDIF(${CPACK_SYSTEM_NAME} MATCHES Windows) + + IF(NOT DEFINED CPACK_PACKAGE_FILE_NAME) + SET(CPACK_PACKAGE_FILE_NAME "${CPACK_SOURCE_PACKAGE_FILE_NAME}-${CPACK_SYSTEM_NAME}") + ENDIF(NOT DEFINED CPACK_PACKAGE_FILE_NAME) + + SET(CPACK_PACKAGE_CONTACT "${PROJECT_CONTACT}") + IF(UNIX) + SET(CPACK_STRIP_FILES "") + SET(CPACK_SOURCE_STRIP_FILES "") +# SET(CPACK_PACKAGE_EXECUTABLES "ccmake" "CMake") + ENDIF(UNIX) + SET(CPACK_SOURCE_IGNORE_FILES "/CVS/" "/build/" "/\\\\.build/" "/\\\\.svn/" "~$") + # include CPack model once all variables are set + INCLUDE(CPack) +ENDIF(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/CMakeModules/cmake_uninstall.cmake.in b/tools/rasm/lzsa-master/src/libdivsufsort/CMakeModules/cmake_uninstall.cmake.in new file mode 100644 index 0000000..8366a83 --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/CMakeModules/cmake_uninstall.cmake.in @@ -0,0 +1,36 @@ +IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") +ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + +FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +STRING(REGEX REPLACE "\n" ";" files "${files}") + +SET(NUM 0) +FOREACH(file ${files}) + IF(EXISTS "$ENV{DESTDIR}${file}") + MESSAGE(STATUS "Looking for \"$ENV{DESTDIR}${file}\" - found") + SET(UNINSTALL_CHECK_${NUM} 1) + ELSE(EXISTS "$ENV{DESTDIR}${file}") + MESSAGE(STATUS "Looking for \"$ENV{DESTDIR}${file}\" - not found") + SET(UNINSTALL_CHECK_${NUM} 0) + ENDIF(EXISTS "$ENV{DESTDIR}${file}") + MATH(EXPR NUM "1 + ${NUM}") +ENDFOREACH(file) + +SET(NUM 0) +FOREACH(file ${files}) + IF(${UNINSTALL_CHECK_${NUM}}) + MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") + EXEC_PROGRAM( + "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + IF(NOT "${rm_retval}" STREQUAL 0) + MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") + ENDIF(NOT "${rm_retval}" STREQUAL 0) + ENDIF(${UNINSTALL_CHECK_${NUM}}) + MATH(EXPR NUM "1 + ${NUM}") +ENDFOREACH(file) + +FILE(REMOVE "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/LICENSE b/tools/rasm/lzsa-master/src/libdivsufsort/LICENSE new file mode 100644 index 0000000..249efa4 --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2003 Yuta Mori 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. diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/README.md b/tools/rasm/lzsa-master/src/libdivsufsort/README.md new file mode 100644 index 0000000..381a188 --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/README.md @@ -0,0 +1,140 @@ +# libdivsufsort + +libdivsufsort is a software library that implements a lightweight suffix array construction algorithm. + +## News +* 2015-03-21: The project has moved from [Google Code](http://code.google.com/p/libdivsufsort/) to [GitHub](https://github.com/y-256/libdivsufsort) + +## Introduction +This library provides a simple and an efficient C API to construct a suffix array and a Burrows-Wheeler transformed string from a given string over a constant-size alphabet. +The algorithm runs in O(n log n) worst-case time using only 5n+O(1) bytes of memory space, where n is the length of +the string. + +## Build requirements +* An ANSI C Compiler (e.g. GNU GCC) +* [CMake](http://www.cmake.org/ "CMake") version 2.4.2 or newer +* CMake-supported build tool + +## Building on GNU/Linux +1. Get the source code from GitHub. You can either + * use git to clone the repository + ``` + git clone https://github.com/y-256/libdivsufsort.git + ``` + * or download a [zip file](../../archive/master.zip) directly +2. Create a `build` directory in the package source directory. +```shell +$ cd libdivsufsort +$ mkdir build +$ cd build +``` +3. Configure the package for your system. +If you want to install to a different location, change the -DCMAKE_INSTALL_PREFIX option. +```shell +$ cmake -DCMAKE_BUILD_TYPE="Release" \ +-DCMAKE_INSTALL_PREFIX="/usr/local" .. +``` +4. Compile the package. +```shell +$ make +``` +5. (Optional) Install the library and header files. +```shell +$ sudo make install +``` + +## API +```c +/* Data types */ +typedef int32_t saint_t; +typedef int32_t saidx_t; +typedef uint8_t sauchar_t; + +/* + * Constructs the suffix array of a given string. + * @param T[0..n-1] The input string. + * @param SA[0..n-1] The output array or suffixes. + * @param n The length of the given string. + * @return 0 if no error occurred, -1 or -2 otherwise. + */ +saint_t +divsufsort(const sauchar_t *T, saidx_t *SA, saidx_t n); + +/* + * Constructs the burrows-wheeler transformed string of a given string. + * @param T[0..n-1] The input string. + * @param U[0..n-1] The output string. (can be T) + * @param A[0..n-1] The temporary array. (can be NULL) + * @param n The length of the given string. + * @return The primary index if no error occurred, -1 or -2 otherwise. + */ +saidx_t +divbwt(const sauchar_t *T, sauchar_t *U, saidx_t *A, saidx_t n); +``` + +## Example Usage +```c +#include +#include +#include + +#include + +int main() { + // intput data + char *Text = "abracadabra"; + int n = strlen(Text); + int i, j; + + // allocate + int *SA = (int *)malloc(n * sizeof(int)); + + // sort + divsufsort((unsigned char *)Text, SA, n); + + // output + for(i = 0; i < n; ++i) { + printf("SA[%2d] = %2d: ", i, SA[i]); + for(j = SA[i]; j < n; ++j) { + printf("%c", Text[j]); + } + printf("$\n"); + } + + // deallocate + free(SA); + + return 0; +} +``` +See the [examples](examples) directory for a few other examples. + +## Benchmarks +See [Benchmarks](https://github.com/y-256/libdivsufsort/blob/wiki/SACA_Benchmarks.md) page for details. + +## License +libdivsufsort is released under the [MIT license](LICENSE "MIT license"). +> The MIT License (MIT) +> +> Copyright (c) 2003 Yuta Mori 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. + +## Author +* Yuta Mori diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/VERSION.cmake b/tools/rasm/lzsa-master/src/libdivsufsort/VERSION.cmake new file mode 100644 index 0000000..3f11ac1 --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/VERSION.cmake @@ -0,0 +1,23 @@ +set(PROJECT_VERSION_MAJOR "2") +set(PROJECT_VERSION_MINOR "0") +set(PROJECT_VERSION_PATCH "2") +set(PROJECT_VERSION_EXTRA "-1") +set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}") +set(PROJECT_VERSION_FULL "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${PROJECT_VERSION_EXTRA}") + +set(LIBRARY_VERSION "3.0.1") +set(LIBRARY_SOVERSION "3") + +## Git revision number ## +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git") + execute_process(COMMAND git describe --tags HEAD + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + OUTPUT_VARIABLE GIT_DESCRIBE_TAGS ERROR_QUIET) + if(GIT_DESCRIBE_TAGS) + string(REGEX REPLACE "^v(.*)" "\\1" GIT_REVISION "${GIT_DESCRIBE_TAGS}") + string(STRIP "${GIT_REVISION}" GIT_REVISION) + if(GIT_REVISION) + set(PROJECT_VERSION_FULL "${GIT_REVISION}") + endif(GIT_REVISION) + endif(GIT_DESCRIBE_TAGS) +endif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git") diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/examples/CMakeLists.txt b/tools/rasm/lzsa-master/src/libdivsufsort/examples/CMakeLists.txt new file mode 100644 index 0000000..e801c81 --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/examples/CMakeLists.txt @@ -0,0 +1,11 @@ +## Add definitions ## +add_definitions(-D_LARGEFILE_SOURCE -D_LARGE_FILES -D_FILE_OFFSET_BITS=64) + +## Targets ## +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../include" + "${CMAKE_CURRENT_BINARY_DIR}/../include") +link_directories("${CMAKE_CURRENT_BINARY_DIR}/../lib") +foreach(src suftest mksary sasearch bwt unbwt) + add_executable(${src} ${src}.c) + target_link_libraries(${src} divsufsort) +endforeach(src) diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/examples/bwt.c b/tools/rasm/lzsa-master/src/libdivsufsort/examples/bwt.c new file mode 100644 index 0000000..5a362d0 --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/examples/bwt.c @@ -0,0 +1,220 @@ +/* + * bwt.c for libdivsufsort + * Copyright (c) 2003-2008 Yuta Mori 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. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include +#if HAVE_STRING_H +# include +#endif +#if HAVE_STDLIB_H +# include +#endif +#if HAVE_MEMORY_H +# include +#endif +#if HAVE_STDDEF_H +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_IO_H && HAVE_FCNTL_H +# include +# include +#endif +#include +#include +#include "lfs.h" + + +static +size_t +write_int(FILE *fp, saidx_t n) { + unsigned char c[4]; + c[0] = (unsigned char)((n >> 0) & 0xff), c[1] = (unsigned char)((n >> 8) & 0xff), + c[2] = (unsigned char)((n >> 16) & 0xff), c[3] = (unsigned char)((n >> 24) & 0xff); + return fwrite(c, sizeof(unsigned char), 4, fp); +} + +static +void +print_help(const char *progname, int status) { + fprintf(stderr, + "bwt, a burrows-wheeler transform program, version %s.\n", + divsufsort_version()); + fprintf(stderr, "usage: %s [-b num] INFILE OUTFILE\n", progname); + fprintf(stderr, " -b num set block size to num MiB [1..512] (default: 32)\n\n"); + exit(status); +} + +int +main(int argc, const char *argv[]) { + FILE *fp, *ofp; + const char *fname, *ofname; + sauchar_t *T; + saidx_t *SA; + LFS_OFF_T n; + size_t m; + saidx_t pidx; + clock_t start,finish; + saint_t i, blocksize = 32, needclose = 3; + + /* Check arguments. */ + if((argc == 1) || + (strcmp(argv[1], "-h") == 0) || + (strcmp(argv[1], "--help") == 0)) { print_help(argv[0], EXIT_SUCCESS); } + if((argc != 3) && (argc != 5)) { print_help(argv[0], EXIT_FAILURE); } + i = 1; + if(argc == 5) { + if(strcmp(argv[i], "-b") != 0) { print_help(argv[0], EXIT_FAILURE); } + blocksize = atoi(argv[i + 1]); + if(blocksize < 0) { blocksize = 1; } + else if(512 < blocksize) { blocksize = 512; } + i += 2; + } + blocksize <<= 20; + + /* Open a file for reading. */ + if(strcmp(argv[i], "-") != 0) { +#if HAVE_FOPEN_S + if(fopen_s(&fp, fname = argv[i], "rb") != 0) { +#else + if((fp = LFS_FOPEN(fname = argv[i], "rb")) == NULL) { +#endif + fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], fname); + perror(NULL); + exit(EXIT_FAILURE); + } + } else { +#if HAVE__SETMODE && HAVE__FILENO + if(_setmode(_fileno(stdin), _O_BINARY) == -1) { + fprintf(stderr, "%s: Cannot set mode: ", argv[0]); + perror(NULL); + exit(EXIT_FAILURE); + } +#endif + fp = stdin; + fname = "stdin"; + needclose ^= 1; + } + i += 1; + + /* Open a file for writing. */ + if(strcmp(argv[i], "-") != 0) { +#if HAVE_FOPEN_S + if(fopen_s(&ofp, ofname = argv[i], "wb") != 0) { +#else + if((ofp = LFS_FOPEN(ofname = argv[i], "wb")) == NULL) { +#endif + fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], ofname); + perror(NULL); + exit(EXIT_FAILURE); + } + } else { +#if HAVE__SETMODE && HAVE__FILENO + if(_setmode(_fileno(stdout), _O_BINARY) == -1) { + fprintf(stderr, "%s: Cannot set mode: ", argv[0]); + perror(NULL); + exit(EXIT_FAILURE); + } +#endif + ofp = stdout; + ofname = "stdout"; + needclose ^= 2; + } + + /* Get the file size. */ + if(LFS_FSEEK(fp, 0, SEEK_END) == 0) { + n = LFS_FTELL(fp); + rewind(fp); + if(n < 0) { + fprintf(stderr, "%s: Cannot ftell `%s': ", argv[0], fname); + perror(NULL); + exit(EXIT_FAILURE); + } + if(0x20000000L < n) { n = 0x20000000L; } + if((blocksize == 0) || (n < blocksize)) { blocksize = (saidx_t)n; } + } else if(blocksize == 0) { blocksize = 32 << 20; } + + /* Allocate 5blocksize bytes of memory. */ + T = (sauchar_t *)malloc(blocksize * sizeof(sauchar_t)); + SA = (saidx_t *)malloc(blocksize * sizeof(saidx_t)); + if((T == NULL) || (SA == NULL)) { + fprintf(stderr, "%s: Cannot allocate memory.\n", argv[0]); + exit(EXIT_FAILURE); + } + + /* Write the blocksize. */ + if(write_int(ofp, blocksize) != 4) { + fprintf(stderr, "%s: Cannot write to `%s': ", argv[0], ofname); + perror(NULL); + exit(EXIT_FAILURE); + } + + fprintf(stderr, " BWT (blocksize %" PRIdSAINT_T ") ... ", blocksize); + start = clock(); + for(n = 0; 0 < (m = fread(T, sizeof(sauchar_t), blocksize, fp)); n += m) { + /* Burrows-Wheeler Transform. */ + pidx = divbwt(T, T, SA, m); + if(pidx < 0) { + fprintf(stderr, "%s (bw_transform): %s.\n", + argv[0], + (pidx == -1) ? "Invalid arguments" : "Cannot allocate memory"); + exit(EXIT_FAILURE); + } + + /* Write the bwted data. */ + if((write_int(ofp, pidx) != 4) || + (fwrite(T, sizeof(sauchar_t), m, ofp) != m)) { + fprintf(stderr, "%s: Cannot write to `%s': ", argv[0], ofname); + perror(NULL); + exit(EXIT_FAILURE); + } + } + if(ferror(fp)) { + fprintf(stderr, "%s: Cannot read from `%s': ", argv[0], fname); + perror(NULL); + exit(EXIT_FAILURE); + } + finish = clock(); + fprintf(stderr, "%" PRIdOFF_T " bytes: %.4f sec\n", + n, (double)(finish - start) / (double)CLOCKS_PER_SEC); + + /* Close files */ + if(needclose & 1) { fclose(fp); } + if(needclose & 2) { fclose(ofp); } + + /* Deallocate memory. */ + free(SA); + free(T); + + return 0; +} diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/examples/mksary.c b/tools/rasm/lzsa-master/src/libdivsufsort/examples/mksary.c new file mode 100644 index 0000000..b48177c --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/examples/mksary.c @@ -0,0 +1,193 @@ +/* + * mksary.c for libdivsufsort + * Copyright (c) 2003-2008 Yuta Mori 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. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include +#if HAVE_STRING_H +# include +#endif +#if HAVE_STDLIB_H +# include +#endif +#if HAVE_MEMORY_H +# include +#endif +#if HAVE_STDDEF_H +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_IO_H && HAVE_FCNTL_H +# include +# include +#endif +#include +#include +#include "lfs.h" + + +static +void +print_help(const char *progname, int status) { + fprintf(stderr, + "mksary, a simple suffix array builder, version %s.\n", + divsufsort_version()); + fprintf(stderr, "usage: %s INFILE OUTFILE\n\n", progname); + exit(status); +} + +int +main(int argc, const char *argv[]) { + FILE *fp, *ofp; + const char *fname, *ofname; + sauchar_t *T; + saidx_t *SA; + LFS_OFF_T n; + clock_t start, finish; + saint_t needclose = 3; + + /* Check arguments. */ + if((argc == 1) || + (strcmp(argv[1], "-h") == 0) || + (strcmp(argv[1], "--help") == 0)) { print_help(argv[0], EXIT_SUCCESS); } + if(argc != 3) { print_help(argv[0], EXIT_FAILURE); } + + /* Open a file for reading. */ + if(strcmp(argv[1], "-") != 0) { +#if HAVE_FOPEN_S + if(fopen_s(&fp, fname = argv[1], "rb") != 0) { +#else + if((fp = LFS_FOPEN(fname = argv[1], "rb")) == NULL) { +#endif + fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], fname); + perror(NULL); + exit(EXIT_FAILURE); + } + } else { +#if HAVE__SETMODE && HAVE__FILENO + if(_setmode(_fileno(stdin), _O_BINARY) == -1) { + fprintf(stderr, "%s: Cannot set mode: ", argv[0]); + perror(NULL); + exit(EXIT_FAILURE); + } +#endif + fp = stdin; + fname = "stdin"; + needclose ^= 1; + } + + /* Open a file for writing. */ + if(strcmp(argv[2], "-") != 0) { +#if HAVE_FOPEN_S + if(fopen_s(&ofp, ofname = argv[2], "wb") != 0) { +#else + if((ofp = LFS_FOPEN(ofname = argv[2], "wb")) == NULL) { +#endif + fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], ofname); + perror(NULL); + exit(EXIT_FAILURE); + } + } else { +#if HAVE__SETMODE && HAVE__FILENO + if(_setmode(_fileno(stdout), _O_BINARY) == -1) { + fprintf(stderr, "%s: Cannot set mode: ", argv[0]); + perror(NULL); + exit(EXIT_FAILURE); + } +#endif + ofp = stdout; + ofname = "stdout"; + needclose ^= 2; + } + + /* Get the file size. */ + if(LFS_FSEEK(fp, 0, SEEK_END) == 0) { + n = LFS_FTELL(fp); + rewind(fp); + if(n < 0) { + fprintf(stderr, "%s: Cannot ftell `%s': ", argv[0], fname); + perror(NULL); + exit(EXIT_FAILURE); + } + if(0x7fffffff <= n) { + fprintf(stderr, "%s: Input file `%s' is too big.\n", argv[0], fname); + exit(EXIT_FAILURE); + } + } else { + fprintf(stderr, "%s: Cannot fseek `%s': ", argv[0], fname); + perror(NULL); + exit(EXIT_FAILURE); + } + + /* Allocate 5blocksize bytes of memory. */ + T = (sauchar_t *)malloc((size_t)n * sizeof(sauchar_t)); + SA = (saidx_t *)malloc((size_t)n * sizeof(saidx_t)); + if((T == NULL) || (SA == NULL)) { + fprintf(stderr, "%s: Cannot allocate memory.\n", argv[0]); + exit(EXIT_FAILURE); + } + + /* Read n bytes of data. */ + if(fread(T, sizeof(sauchar_t), (size_t)n, fp) != (size_t)n) { + fprintf(stderr, "%s: %s `%s': ", + argv[0], + (ferror(fp) || !feof(fp)) ? "Cannot read from" : "Unexpected EOF in", + fname); + perror(NULL); + exit(EXIT_FAILURE); + } + if(needclose & 1) { fclose(fp); } + + /* Construct the suffix array. */ + fprintf(stderr, "%s: %" PRIdOFF_T " bytes ... ", fname, n); + start = clock(); + if(divsufsort(T, SA, (saidx_t)n) != 0) { + fprintf(stderr, "%s: Cannot allocate memory.\n", argv[0]); + exit(EXIT_FAILURE); + } + finish = clock(); + fprintf(stderr, "%.4f sec\n", (double)(finish - start) / (double)CLOCKS_PER_SEC); + + /* Write the suffix array. */ + if(fwrite(SA, sizeof(saidx_t), (size_t)n, ofp) != (size_t)n) { + fprintf(stderr, "%s: Cannot write to `%s': ", argv[0], ofname); + perror(NULL); + exit(EXIT_FAILURE); + } + if(needclose & 2) { fclose(ofp); } + + /* Deallocate memory. */ + free(SA); + free(T); + + return 0; +} diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/examples/sasearch.c b/tools/rasm/lzsa-master/src/libdivsufsort/examples/sasearch.c new file mode 100644 index 0000000..7e5ca4f --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/examples/sasearch.c @@ -0,0 +1,165 @@ +/* + * sasearch.c for libdivsufsort + * Copyright (c) 2003-2008 Yuta Mori 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. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include +#if HAVE_STRING_H +# include +#endif +#if HAVE_STDLIB_H +# include +#endif +#if HAVE_MEMORY_H +# include +#endif +#if HAVE_STDDEF_H +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_IO_H && HAVE_FCNTL_H +# include +# include +#endif +#include +#include "lfs.h" + + +static +void +print_help(const char *progname, int status) { + fprintf(stderr, + "sasearch, a simple SA-based full-text search tool, version %s\n", + divsufsort_version()); + fprintf(stderr, "usage: %s PATTERN FILE SAFILE\n\n", progname); + exit(status); +} + +int +main(int argc, const char *argv[]) { + FILE *fp; + const char *P; + sauchar_t *T; + saidx_t *SA; + LFS_OFF_T n; + size_t Psize; + saidx_t i, size, left; + + if((argc == 1) || + (strcmp(argv[1], "-h") == 0) || + (strcmp(argv[1], "--help") == 0)) { print_help(argv[0], EXIT_SUCCESS); } + if(argc != 4) { print_help(argv[0], EXIT_FAILURE); } + + P = argv[1]; + Psize = strlen(P); + + /* Open a file for reading. */ +#if HAVE_FOPEN_S + if(fopen_s(&fp, argv[2], "rb") != 0) { +#else + if((fp = LFS_FOPEN(argv[2], "rb")) == NULL) { +#endif + fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], argv[2]); + perror(NULL); + exit(EXIT_FAILURE); + } + + /* Get the file size. */ + if(LFS_FSEEK(fp, 0, SEEK_END) == 0) { + n = LFS_FTELL(fp); + rewind(fp); + if(n < 0) { + fprintf(stderr, "%s: Cannot ftell `%s': ", argv[0], argv[2]); + perror(NULL); + exit(EXIT_FAILURE); + } + } else { + fprintf(stderr, "%s: Cannot fseek `%s': ", argv[0], argv[2]); + perror(NULL); + exit(EXIT_FAILURE); + } + + /* Allocate 5n bytes of memory. */ + T = (sauchar_t *)malloc((size_t)n * sizeof(sauchar_t)); + SA = (saidx_t *)malloc((size_t)n * sizeof(saidx_t)); + if((T == NULL) || (SA == NULL)) { + fprintf(stderr, "%s: Cannot allocate memory.\n", argv[0]); + exit(EXIT_FAILURE); + } + + /* Read n bytes of data. */ + if(fread(T, sizeof(sauchar_t), (size_t)n, fp) != (size_t)n) { + fprintf(stderr, "%s: %s `%s': ", + argv[0], + (ferror(fp) || !feof(fp)) ? "Cannot read from" : "Unexpected EOF in", + argv[2]); + perror(NULL); + exit(EXIT_FAILURE); + } + fclose(fp); + + /* Open the SA file for reading. */ +#if HAVE_FOPEN_S + if(fopen_s(&fp, argv[3], "rb") != 0) { +#else + if((fp = LFS_FOPEN(argv[3], "rb")) == NULL) { +#endif + fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], argv[3]); + perror(NULL); + exit(EXIT_FAILURE); + } + + /* Read n * sizeof(saidx_t) bytes of data. */ + if(fread(SA, sizeof(saidx_t), (size_t)n, fp) != (size_t)n) { + fprintf(stderr, "%s: %s `%s': ", + argv[0], + (ferror(fp) || !feof(fp)) ? "Cannot read from" : "Unexpected EOF in", + argv[3]); + perror(NULL); + exit(EXIT_FAILURE); + } + fclose(fp); + + /* Search and print */ + size = sa_search(T, (saidx_t)n, + (const sauchar_t *)P, (saidx_t)Psize, + SA, (saidx_t)n, &left); + for(i = 0; i < size; ++i) { + fprintf(stdout, "%" PRIdSAIDX_T "\n", SA[left + i]); + } + + /* Deallocate memory. */ + free(SA); + free(T); + + return 0; +} diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/examples/suftest.c b/tools/rasm/lzsa-master/src/libdivsufsort/examples/suftest.c new file mode 100644 index 0000000..71892ac --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/examples/suftest.c @@ -0,0 +1,164 @@ +/* + * suftest.c for libdivsufsort + * Copyright (c) 2003-2008 Yuta Mori 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. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include +#if HAVE_STRING_H +# include +#endif +#if HAVE_STDLIB_H +# include +#endif +#if HAVE_MEMORY_H +# include +#endif +#if HAVE_STDDEF_H +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_IO_H && HAVE_FCNTL_H +# include +# include +#endif +#include +#include +#include "lfs.h" + + +static +void +print_help(const char *progname, int status) { + fprintf(stderr, + "suftest, a suffixsort tester, version %s.\n", + divsufsort_version()); + fprintf(stderr, "usage: %s FILE\n\n", progname); + exit(status); +} + +int +main(int argc, const char *argv[]) { + FILE *fp; + const char *fname; + sauchar_t *T; + saidx_t *SA; + LFS_OFF_T n; + clock_t start, finish; + saint_t needclose = 1; + + /* Check arguments. */ + if((argc == 1) || + (strcmp(argv[1], "-h") == 0) || + (strcmp(argv[1], "--help") == 0)) { print_help(argv[0], EXIT_SUCCESS); } + if(argc != 2) { print_help(argv[0], EXIT_FAILURE); } + + /* Open a file for reading. */ + if(strcmp(argv[1], "-") != 0) { +#if HAVE_FOPEN_S + if(fopen_s(&fp, fname = argv[1], "rb") != 0) { +#else + if((fp = LFS_FOPEN(fname = argv[1], "rb")) == NULL) { +#endif + fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], fname); + perror(NULL); + exit(EXIT_FAILURE); + } + } else { +#if HAVE__SETMODE && HAVE__FILENO + if(_setmode(_fileno(stdin), _O_BINARY) == -1) { + fprintf(stderr, "%s: Cannot set mode: ", argv[0]); + perror(NULL); + exit(EXIT_FAILURE); + } +#endif + fp = stdin; + fname = "stdin"; + needclose = 0; + } + + /* Get the file size. */ + if(LFS_FSEEK(fp, 0, SEEK_END) == 0) { + n = LFS_FTELL(fp); + rewind(fp); + if(n < 0) { + fprintf(stderr, "%s: Cannot ftell `%s': ", argv[0], fname); + perror(NULL); + exit(EXIT_FAILURE); + } + if(0x7fffffff <= n) { + fprintf(stderr, "%s: Input file `%s' is too big.\n", argv[0], fname); + exit(EXIT_FAILURE); + } + } else { + fprintf(stderr, "%s: Cannot fseek `%s': ", argv[0], fname); + perror(NULL); + exit(EXIT_FAILURE); + } + + /* Allocate 5n bytes of memory. */ + T = (sauchar_t *)malloc((size_t)n * sizeof(sauchar_t)); + SA = (saidx_t *)malloc((size_t)n * sizeof(saidx_t)); + if((T == NULL) || (SA == NULL)) { + fprintf(stderr, "%s: Cannot allocate memory.\n", argv[0]); + exit(EXIT_FAILURE); + } + + /* Read n bytes of data. */ + if(fread(T, sizeof(sauchar_t), (size_t)n, fp) != (size_t)n) { + fprintf(stderr, "%s: %s `%s': ", + argv[0], + (ferror(fp) || !feof(fp)) ? "Cannot read from" : "Unexpected EOF in", + argv[1]); + perror(NULL); + exit(EXIT_FAILURE); + } + if(needclose & 1) { fclose(fp); } + + /* Construct the suffix array. */ + fprintf(stderr, "%s: %" PRIdOFF_T " bytes ... ", fname, n); + start = clock(); + if(divsufsort(T, SA, (saidx_t)n) != 0) { + fprintf(stderr, "%s: Cannot allocate memory.\n", argv[0]); + exit(EXIT_FAILURE); + } + finish = clock(); + fprintf(stderr, "%.4f sec\n", (double)(finish - start) / (double)CLOCKS_PER_SEC); + + /* Check the suffix array. */ + if(sufcheck(T, SA, (saidx_t)n, 1) != 0) { exit(EXIT_FAILURE); } + + /* Deallocate memory. */ + free(SA); + free(T); + + return 0; +} diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/examples/unbwt.c b/tools/rasm/lzsa-master/src/libdivsufsort/examples/unbwt.c new file mode 100644 index 0000000..c0f19e9 --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/examples/unbwt.c @@ -0,0 +1,207 @@ +/* + * unbwt.c for libdivsufsort + * Copyright (c) 2003-2008 Yuta Mori 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. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include +#if HAVE_STRING_H +# include +#endif +#if HAVE_STDLIB_H +# include +#endif +#if HAVE_MEMORY_H +# include +#endif +#if HAVE_STDDEF_H +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_IO_H && HAVE_FCNTL_H +# include +# include +#endif +#include +#include +#include "lfs.h" + + +static +size_t +read_int(FILE *fp, saidx_t *n) { + unsigned char c[4]; + size_t m = fread(c, sizeof(unsigned char), 4, fp); + if(m == 4) { + *n = (c[0] << 0) | (c[1] << 8) | + (c[2] << 16) | (c[3] << 24); + } + return m; +} + +static +void +print_help(const char *progname, int status) { + fprintf(stderr, + "unbwt, an inverse burrows-wheeler transform program, version %s.\n", + divsufsort_version()); + fprintf(stderr, "usage: %s INFILE OUTFILE\n\n", progname); + exit(status); +} + +int +main(int argc, const char *argv[]) { + FILE *fp, *ofp; + const char *fname, *ofname; + sauchar_t *T; + saidx_t *A; + LFS_OFF_T n; + size_t m; + saidx_t pidx; + clock_t start, finish; + saint_t err, blocksize, needclose = 3; + + /* Check arguments. */ + if((argc == 1) || + (strcmp(argv[1], "-h") == 0) || + (strcmp(argv[1], "--help") == 0)) { print_help(argv[0], EXIT_SUCCESS); } + if(argc != 3) { print_help(argv[0], EXIT_FAILURE); } + + /* Open a file for reading. */ + if(strcmp(argv[1], "-") != 0) { +#if HAVE_FOPEN_S + if(fopen_s(&fp, fname = argv[1], "rb") != 0) { +#else + if((fp = LFS_FOPEN(fname = argv[1], "rb")) == NULL) { +#endif + fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], fname); + perror(NULL); + exit(EXIT_FAILURE); + } + } else { +#if HAVE__SETMODE && HAVE__FILENO + if(_setmode(_fileno(stdin), _O_BINARY) == -1) { + fprintf(stderr, "%s: Cannot set mode: ", argv[0]); + perror(NULL); + exit(EXIT_FAILURE); + } +#endif + fp = stdin; + fname = "stdin"; + needclose ^= 1; + } + + /* Open a file for writing. */ + if(strcmp(argv[2], "-") != 0) { +#if HAVE_FOPEN_S + if(fopen_s(&ofp, ofname = argv[2], "wb") != 0) { +#else + if((ofp = LFS_FOPEN(ofname = argv[2], "wb")) == NULL) { +#endif + fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], ofname); + perror(NULL); + exit(EXIT_FAILURE); + } + } else { +#if HAVE__SETMODE && HAVE__FILENO + if(_setmode(_fileno(stdout), _O_BINARY) == -1) { + fprintf(stderr, "%s: Cannot set mode: ", argv[0]); + perror(NULL); + exit(EXIT_FAILURE); + } +#endif + ofp = stdout; + ofname = "stdout"; + needclose ^= 2; + } + + /* Read the blocksize. */ + if(read_int(fp, &blocksize) != 4) { + fprintf(stderr, "%s: Cannot read from `%s': ", argv[0], fname); + perror(NULL); + exit(EXIT_FAILURE); + } + + /* Allocate 5blocksize bytes of memory. */ + T = (sauchar_t *)malloc(blocksize * sizeof(sauchar_t)); + A = (saidx_t *)malloc(blocksize * sizeof(saidx_t)); + if((T == NULL) || (A == NULL)) { + fprintf(stderr, "%s: Cannot allocate memory.\n", argv[0]); + exit(EXIT_FAILURE); + } + + fprintf(stderr, "UnBWT (blocksize %" PRIdSAINT_T ") ... ", blocksize); + start = clock(); + for(n = 0; (m = read_int(fp, &pidx)) != 0; n += m) { + /* Read blocksize bytes of data. */ + if((m != 4) || ((m = fread(T, sizeof(sauchar_t), blocksize, fp)) == 0)) { + fprintf(stderr, "%s: %s `%s': ", + argv[0], + (ferror(fp) || !feof(fp)) ? "Cannot read from" : "Unexpected EOF in", + fname); + perror(NULL); + exit(EXIT_FAILURE); + } + + /* Inverse Burrows-Wheeler Transform. */ + if((err = inverse_bw_transform(T, T, A, m, pidx)) != 0) { + fprintf(stderr, "%s (reverseBWT): %s.\n", + argv[0], + (err == -1) ? "Invalid data" : "Cannot allocate memory"); + exit(EXIT_FAILURE); + } + + /* Write m bytes of data. */ + if(fwrite(T, sizeof(sauchar_t), m, ofp) != m) { + fprintf(stderr, "%s: Cannot write to `%s': ", argv[0], ofname); + perror(NULL); + exit(EXIT_FAILURE); + } + } + if(ferror(fp)) { + fprintf(stderr, "%s: Cannot read from `%s': ", argv[0], fname); + perror(NULL); + exit(EXIT_FAILURE); + } + finish = clock(); + fprintf(stderr, "%" PRIdOFF_T " bytes: %.4f sec\n", + n, (double)(finish - start) / (double)CLOCKS_PER_SEC); + + /* Close files */ + if(needclose & 1) { fclose(fp); } + if(needclose & 2) { fclose(ofp); } + + /* Deallocate memory. */ + free(A); + free(T); + + return 0; +} diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/include/CMakeLists.txt b/tools/rasm/lzsa-master/src/libdivsufsort/include/CMakeLists.txt new file mode 100644 index 0000000..37781cc --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/include/CMakeLists.txt @@ -0,0 +1,162 @@ +include(CheckIncludeFiles) +include(CheckIncludeFile) +include(CheckSymbolExists) +include(CheckTypeSize) +include(CheckFunctionKeywords) +include(CheckLFS) + +## Checks for header files ## +check_include_file("inttypes.h" HAVE_INTTYPES_H) +check_include_file("memory.h" HAVE_MEMORY_H) +check_include_file("stddef.h" HAVE_STDDEF_H) +check_include_file("stdint.h" HAVE_STDINT_H) +check_include_file("stdlib.h" HAVE_STDLIB_H) +check_include_file("string.h" HAVE_STRING_H) +check_include_file("strings.h" HAVE_STRINGS_H) +check_include_file("sys/types.h" HAVE_SYS_TYPES_H) +if(HAVE_INTTYPES_H) + set(INCFILE "#include ") +elseif(HAVE_STDINT_H) + set(INCFILE "#include ") +else(HAVE_INTTYPES_H) + set(INCFILE "") +endif(HAVE_INTTYPES_H) + +## create configuration files from .cmake file ## +if(BUILD_EXAMPLES) + ## Checks for WinIO ## + if(WIN32) + check_include_file("io.h" HAVE_IO_H) + check_include_file("fcntl.h" HAVE_FCNTL_H) + check_symbol_exists("_setmode" "io.h;fcntl.h" HAVE__SETMODE) + if(NOT HAVE__SETMODE) + check_symbol_exists("setmode" "io.h;fcntl.h" HAVE_SETMODE) + endif(NOT HAVE__SETMODE) + check_symbol_exists("_fileno" "stdio.h" HAVE__FILENO) + check_symbol_exists("fopen_s" "stdio.h" HAVE_FOPEN_S) + check_symbol_exists("_O_BINARY" "fcntl.h" HAVE__O_BINARY) + endif(WIN32) + + ## Checks for large file support ## + check_lfs(WITH_LFS) + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/lfs.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/lfs.h" @ONLY) +endif(BUILD_EXAMPLES) + +## generate config.h ## +check_function_keywords("inline;__inline;__inline__;__declspec(dllexport);__declspec(dllimport)") +if(HAVE_INLINE) + set(INLINE "inline") +elseif(HAVE___INLINE) + set(INLINE "__inline") +elseif(HAVE___INLINE__) + set(INLINE "__inline__") +else(HAVE_INLINE) + set(INLINE "") +endif(HAVE_INLINE) +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/config.h") + +## Checks for types ## +# sauchar_t (8bit) +check_type_size("uint8_t" UINT8_T) +if(HAVE_UINT8_T) + set(SAUCHAR_TYPE "uint8_t") +else(HAVE_UINT8_T) + check_type_size("unsigned char" SIZEOF_UNSIGNED_CHAR) + if("${SIZEOF_UNSIGNED_CHAR}" STREQUAL "1") + set(SAUCHAR_TYPE "unsigned char") + else("${SIZEOF_UNSIGNED_CHAR}" STREQUAL "1") + message(FATAL_ERROR "Cannot find unsigned 8-bit integer type") + endif("${SIZEOF_UNSIGNED_CHAR}" STREQUAL "1") +endif(HAVE_UINT8_T) +# saint_t (32bit) +check_type_size("int32_t" INT32_T) +if(HAVE_INT32_T) + set(SAINT32_TYPE "int32_t") + check_symbol_exists("PRId32" "inttypes.h" HAVE_PRID32) + if(HAVE_PRID32) + set(SAINT32_PRId "PRId32") + else(HAVE_PRID32) + set(SAINT32_PRId "\"d\"") + endif(HAVE_PRID32) +else(HAVE_INT32_T) + check_type_size("int" SIZEOF_INT) + check_type_size("long" SIZEOF_LONG) + check_type_size("short" SIZEOF_SHORT) + check_type_size("__int32" SIZEOF___INT32) + if("${SIZEOF_INT}" STREQUAL "4") + set(SAINT32_TYPE "int") + set(SAINT32_PRId "\"d\"") + elseif("${SIZEOF_LONG}" STREQUAL "4") + set(SAINT32_TYPE "long") + set(SAINT32_PRId "\"ld\"") + elseif("${SIZEOF_SHORT}" STREQUAL "4") + set(SAINT32_TYPE "short") + set(SAINT32_PRId "\"d\"") + elseif("${SIZEOF___INT32}" STREQUAL "4") + set(SAINT32_TYPE "__int32") + set(SAINT32_PRId "\"d\"") + else("${SIZEOF_INT}" STREQUAL "4") + message(FATAL_ERROR "Cannot find 32-bit integer type") + endif("${SIZEOF_INT}" STREQUAL "4") +endif(HAVE_INT32_T) +# saint64_t (64bit) +if(BUILD_DIVSUFSORT64) + check_type_size("int64_t" INT64_T) + if(HAVE_INT64_T) + set(SAINT64_TYPE "int64_t") + check_symbol_exists("PRId64" "inttypes.h" HAVE_PRID64) + if(HAVE_PRID64) + set(SAINT64_PRId "PRId64") + else(HAVE_PRID64) + set(SAINT64_PRId "\"lld\"") + endif(HAVE_PRID64) + else(HAVE_INT64_T) + check_type_size("int" SIZEOF_INT) + check_type_size("long" SIZEOF_LONG) + check_type_size("long long" SIZEOF_LONG_LONG) + check_type_size("__int64" SIZEOF___INT64) + if("${SIZEOF_INT}" STREQUAL "8") + set(SAINT64_TYPE "int") + set(SAINT64_PRId "\"d\"") + elseif("${SIZEOF_LONG}" STREQUAL "8") + set(SAINT64_TYPE "long") + set(SAINT64_PRId "\"ld\"") + elseif("${SIZEOF_LONG_LONG}" STREQUAL "8") + set(SAINT64_TYPE "long long") + set(SAINT64_PRId "\"lld\"") + elseif("${SIZEOF___INT64}" STREQUAL "8") + set(SAINT64_TYPE "__int64") + set(SAINT64_PRId "\"I64d\"") + else("${SIZEOF_INT}" STREQUAL "8") + message(SEND_ERROR "Cannot find 64-bit integer type") + set(BUILD_DIVSUFSORT64 OFF) + endif("${SIZEOF_INT}" STREQUAL "8") + endif(HAVE_INT64_T) +endif(BUILD_DIVSUFSORT64) + +## generate divsufsort.h ## +set(DIVSUFSORT_IMPORT "") +set(DIVSUFSORT_EXPORT "") +if(BUILD_SHARED_LIBS) + if(HAVE___DECLSPEC_DLLIMPORT_) + set(DIVSUFSORT_IMPORT "__declspec(dllimport)") + endif(HAVE___DECLSPEC_DLLIMPORT_) + if(HAVE___DECLSPEC_DLLEXPORT_) + set(DIVSUFSORT_EXPORT "__declspec(dllexport)") + endif(HAVE___DECLSPEC_DLLEXPORT_) +endif(BUILD_SHARED_LIBS) +set(W64BIT "") +set(SAINDEX_TYPE "${SAINT32_TYPE}") +set(SAINDEX_PRId "${SAINT32_PRId}") +set(SAINT_PRId "${SAINT32_PRId}") +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/divsufsort.h.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/divsufsort.h" @ONLY) +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/divsufsort.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +if(BUILD_DIVSUFSORT64) + set(W64BIT "64") + set(SAINDEX_TYPE "${SAINT64_TYPE}") + set(SAINDEX_PRId "${SAINT64_PRId}") + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/divsufsort.h.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/divsufsort64.h" @ONLY) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/divsufsort64.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +endif(BUILD_DIVSUFSORT64) diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/include/config.h.cmake b/tools/rasm/lzsa-master/src/libdivsufsort/include/config.h.cmake new file mode 100644 index 0000000..6a1cf47 --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/include/config.h.cmake @@ -0,0 +1,81 @@ +/* + * config.h for libdivsufsort + * Copyright (c) 2003-2008 Yuta Mori 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 _CONFIG_H +#define _CONFIG_H 1 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** Define to the version of this package. **/ +#cmakedefine PROJECT_VERSION_FULL "${PROJECT_VERSION_FULL}" + +/** Define to 1 if you have the header files. **/ +#cmakedefine HAVE_INTTYPES_H 1 +#cmakedefine HAVE_STDDEF_H 1 +#cmakedefine HAVE_STDINT_H 1 +#cmakedefine HAVE_STDLIB_H 1 +#cmakedefine HAVE_STRING_H 1 +#cmakedefine HAVE_STRINGS_H 1 +#cmakedefine HAVE_MEMORY_H 1 +#cmakedefine HAVE_SYS_TYPES_H 1 + +/** for WinIO **/ +#cmakedefine HAVE_IO_H 1 +#cmakedefine HAVE_FCNTL_H 1 +#cmakedefine HAVE__SETMODE 1 +#cmakedefine HAVE_SETMODE 1 +#cmakedefine HAVE__FILENO 1 +#cmakedefine HAVE_FOPEN_S 1 +#cmakedefine HAVE__O_BINARY 1 +#ifndef HAVE__SETMODE +# if HAVE_SETMODE +# define _setmode setmode +# define HAVE__SETMODE 1 +# endif +# if HAVE__SETMODE && !HAVE__O_BINARY +# define _O_BINARY 0 +# define HAVE__O_BINARY 1 +# endif +#endif + +/** for inline **/ +#ifndef INLINE +# define INLINE @INLINE@ +#endif + +/** for VC++ warning **/ +#ifdef _MSC_VER +#pragma warning(disable: 4127) +#endif + + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* _CONFIG_H */ diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/include/divsufsort.h b/tools/rasm/lzsa-master/src/libdivsufsort/include/divsufsort.h new file mode 100755 index 0000000..7ebb412 --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/include/divsufsort.h @@ -0,0 +1,189 @@ +/* + * divsufsort.h for libdivsufsort + * Copyright (c) 2003-2008 Yuta Mori 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 _DIVSUFSORT_H +#define _DIVSUFSORT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define DIVSUFSORT_API + +/*- Datatypes -*/ +#ifndef SAUCHAR_T +#define SAUCHAR_T +typedef unsigned char sauchar_t; +#endif /* SAUCHAR_T */ +#ifndef SAINT_T +#define SAINT_T +typedef int saint_t; +#endif /* SAINT_T */ +#ifndef SAIDX_T +#define SAIDX_T +typedef int saidx_t; +#endif /* SAIDX_T */ +#ifndef PRIdSAIDX_T +#define PRIdSAIDX_T "d" +#endif + +/*- divsufsort context */ +typedef struct _divsufsort_ctx_t { + saidx_t *bucket_A; + saidx_t *bucket_B; +} divsufsort_ctx_t; + +/*- Prototypes -*/ + +/** + * Initialize suffix array context + * + * @return 0 for success, or non-zero in case of an error + */ +int divsufsort_init(divsufsort_ctx_t *ctx); + +/** + * Destroy suffix array context + * + * @param ctx suffix array context to destroy + */ +void divsufsort_destroy(divsufsort_ctx_t *ctx); + +/** + * Constructs the suffix array of a given string. + * @param ctx suffix array context + * @param T[0..n-1] The input string. + * @param SA[0..n-1] The output array of suffixes. + * @param n The length of the given string. + * @return 0 if no error occurred, -1 or -2 otherwise. + */ +DIVSUFSORT_API +saint_t divsufsort_build_array(divsufsort_ctx_t *ctx, const sauchar_t *T, saidx_t *SA, saidx_t n); + +#if 0 +/** + * Constructs the burrows-wheeler transformed string of a given string. + * @param T[0..n-1] The input string. + * @param U[0..n-1] The output string. (can be T) + * @param A[0..n-1] The temporary array. (can be NULL) + * @param n The length of the given string. + * @return The primary index if no error occurred, -1 or -2 otherwise. + */ +DIVSUFSORT_API +saidx_t +divbwt(const sauchar_t *T, sauchar_t *U, saidx_t *A, saidx_t n); + +/** + * Returns the version of the divsufsort library. + * @return The version number string. + */ +DIVSUFSORT_API +const char * +divsufsort_version(void); + + +/** + * Constructs the burrows-wheeler transformed string of a given string and suffix array. + * @param T[0..n-1] The input string. + * @param U[0..n-1] The output string. (can be T) + * @param SA[0..n-1] The suffix array. (can be NULL) + * @param n The length of the given string. + * @param idx The output primary index. + * @return 0 if no error occurred, -1 or -2 otherwise. + */ +DIVSUFSORT_API +saint_t +bw_transform(const sauchar_t *T, sauchar_t *U, + saidx_t *SA /* can NULL */, + saidx_t n, saidx_t *idx); + +/** + * Inverse BW-transforms a given BWTed string. + * @param T[0..n-1] The input string. + * @param U[0..n-1] The output string. (can be T) + * @param A[0..n-1] The temporary array. (can be NULL) + * @param n The length of the given string. + * @param idx The primary index. + * @return 0 if no error occurred, -1 or -2 otherwise. + */ +DIVSUFSORT_API +saint_t +inverse_bw_transform(const sauchar_t *T, sauchar_t *U, + saidx_t *A /* can NULL */, + saidx_t n, saidx_t idx); + +/** + * Checks the correctness of a given suffix array. + * @param T[0..n-1] The input string. + * @param SA[0..n-1] The input suffix array. + * @param n The length of the given string. + * @param verbose The verbose mode. + * @return 0 if no error occurred. + */ +DIVSUFSORT_API +saint_t +sufcheck(const sauchar_t *T, const saidx_t *SA, saidx_t n, saint_t verbose); + +/** + * Search for the pattern P in the string T. + * @param T[0..Tsize-1] The input string. + * @param Tsize The length of the given string. + * @param P[0..Psize-1] The input pattern string. + * @param Psize The length of the given pattern string. + * @param SA[0..SAsize-1] The input suffix array. + * @param SAsize The length of the given suffix array. + * @param idx The output index. + * @return The count of matches if no error occurred, -1 otherwise. + */ +DIVSUFSORT_API +saidx_t +sa_search(const sauchar_t *T, saidx_t Tsize, + const sauchar_t *P, saidx_t Psize, + const saidx_t *SA, saidx_t SAsize, + saidx_t *left); + +/** + * Search for the character c in the string T. + * @param T[0..Tsize-1] The input string. + * @param Tsize The length of the given string. + * @param SA[0..SAsize-1] The input suffix array. + * @param SAsize The length of the given suffix array. + * @param c The input character. + * @param idx The output index. + * @return The count of matches if no error occurred, -1 otherwise. + */ +DIVSUFSORT_API +saidx_t +sa_simplesearch(const sauchar_t *T, saidx_t Tsize, + const saidx_t *SA, saidx_t SAsize, + saint_t c, saidx_t *left); +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* _DIVSUFSORT_H */ diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/include/divsufsort.h.cmake b/tools/rasm/lzsa-master/src/libdivsufsort/include/divsufsort.h.cmake new file mode 100644 index 0000000..bcaba7c --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/include/divsufsort.h.cmake @@ -0,0 +1,180 @@ +/* + * divsufsort@W64BIT@.h for libdivsufsort@W64BIT@ + * Copyright (c) 2003-2008 Yuta Mori 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 _DIVSUFSORT@W64BIT@_H +#define _DIVSUFSORT@W64BIT@_H 1 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +@INCFILE@ + +#ifndef DIVSUFSORT_API +# ifdef DIVSUFSORT_BUILD_DLL +# define DIVSUFSORT_API @DIVSUFSORT_EXPORT@ +# else +# define DIVSUFSORT_API @DIVSUFSORT_IMPORT@ +# endif +#endif + +/*- Datatypes -*/ +#ifndef SAUCHAR_T +#define SAUCHAR_T +typedef @SAUCHAR_TYPE@ sauchar_t; +#endif /* SAUCHAR_T */ +#ifndef SAINT_T +#define SAINT_T +typedef @SAINT32_TYPE@ saint_t; +#endif /* SAINT_T */ +#ifndef SAIDX@W64BIT@_T +#define SAIDX@W64BIT@_T +typedef @SAINDEX_TYPE@ saidx@W64BIT@_t; +#endif /* SAIDX@W64BIT@_T */ +#ifndef PRIdSAINT_T +#define PRIdSAINT_T @SAINT_PRId@ +#endif /* PRIdSAINT_T */ +#ifndef PRIdSAIDX@W64BIT@_T +#define PRIdSAIDX@W64BIT@_T @SAINDEX_PRId@ +#endif /* PRIdSAIDX@W64BIT@_T */ + + +/*- Prototypes -*/ + +/** + * Constructs the suffix array of a given string. + * @param T[0..n-1] The input string. + * @param SA[0..n-1] The output array of suffixes. + * @param n The length of the given string. + * @return 0 if no error occurred, -1 or -2 otherwise. + */ +DIVSUFSORT_API +saint_t +divsufsort@W64BIT@(const sauchar_t *T, saidx@W64BIT@_t *SA, saidx@W64BIT@_t n); + +/** + * Constructs the burrows-wheeler transformed string of a given string. + * @param T[0..n-1] The input string. + * @param U[0..n-1] The output string. (can be T) + * @param A[0..n-1] The temporary array. (can be NULL) + * @param n The length of the given string. + * @return The primary index if no error occurred, -1 or -2 otherwise. + */ +DIVSUFSORT_API +saidx@W64BIT@_t +divbwt@W64BIT@(const sauchar_t *T, sauchar_t *U, saidx@W64BIT@_t *A, saidx@W64BIT@_t n); + +/** + * Returns the version of the divsufsort library. + * @return The version number string. + */ +DIVSUFSORT_API +const char * +divsufsort@W64BIT@_version(void); + + +/** + * Constructs the burrows-wheeler transformed string of a given string and suffix array. + * @param T[0..n-1] The input string. + * @param U[0..n-1] The output string. (can be T) + * @param SA[0..n-1] The suffix array. (can be NULL) + * @param n The length of the given string. + * @param idx The output primary index. + * @return 0 if no error occurred, -1 or -2 otherwise. + */ +DIVSUFSORT_API +saint_t +bw_transform@W64BIT@(const sauchar_t *T, sauchar_t *U, + saidx@W64BIT@_t *SA /* can NULL */, + saidx@W64BIT@_t n, saidx@W64BIT@_t *idx); + +/** + * Inverse BW-transforms a given BWTed string. + * @param T[0..n-1] The input string. + * @param U[0..n-1] The output string. (can be T) + * @param A[0..n-1] The temporary array. (can be NULL) + * @param n The length of the given string. + * @param idx The primary index. + * @return 0 if no error occurred, -1 or -2 otherwise. + */ +DIVSUFSORT_API +saint_t +inverse_bw_transform@W64BIT@(const sauchar_t *T, sauchar_t *U, + saidx@W64BIT@_t *A /* can NULL */, + saidx@W64BIT@_t n, saidx@W64BIT@_t idx); + +/** + * Checks the correctness of a given suffix array. + * @param T[0..n-1] The input string. + * @param SA[0..n-1] The input suffix array. + * @param n The length of the given string. + * @param verbose The verbose mode. + * @return 0 if no error occurred. + */ +DIVSUFSORT_API +saint_t +sufcheck@W64BIT@(const sauchar_t *T, const saidx@W64BIT@_t *SA, saidx@W64BIT@_t n, saint_t verbose); + +/** + * Search for the pattern P in the string T. + * @param T[0..Tsize-1] The input string. + * @param Tsize The length of the given string. + * @param P[0..Psize-1] The input pattern string. + * @param Psize The length of the given pattern string. + * @param SA[0..SAsize-1] The input suffix array. + * @param SAsize The length of the given suffix array. + * @param idx The output index. + * @return The count of matches if no error occurred, -1 otherwise. + */ +DIVSUFSORT_API +saidx@W64BIT@_t +sa_search@W64BIT@(const sauchar_t *T, saidx@W64BIT@_t Tsize, + const sauchar_t *P, saidx@W64BIT@_t Psize, + const saidx@W64BIT@_t *SA, saidx@W64BIT@_t SAsize, + saidx@W64BIT@_t *left); + +/** + * Search for the character c in the string T. + * @param T[0..Tsize-1] The input string. + * @param Tsize The length of the given string. + * @param SA[0..SAsize-1] The input suffix array. + * @param SAsize The length of the given suffix array. + * @param c The input character. + * @param idx The output index. + * @return The count of matches if no error occurred, -1 otherwise. + */ +DIVSUFSORT_API +saidx@W64BIT@_t +sa_simplesearch@W64BIT@(const sauchar_t *T, saidx@W64BIT@_t Tsize, + const saidx@W64BIT@_t *SA, saidx@W64BIT@_t SAsize, + saint_t c, saidx@W64BIT@_t *left); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* _DIVSUFSORT@W64BIT@_H */ diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/include/divsufsort_config.h b/tools/rasm/lzsa-master/src/libdivsufsort/include/divsufsort_config.h new file mode 100644 index 0000000..4054a8a --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/include/divsufsort_config.h @@ -0,0 +1,9 @@ +#define HAVE_STRING_H 1 +#define HAVE_STDLIB_H 1 +#define HAVE_MEMORY_H 1 +#define HAVE_STDINT_H 1 +#define INLINE inline + +#ifdef _MSC_VER +#pragma warning( disable : 4244 ) +#endif /* _MSC_VER */ diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/include/divsufsort_private.h b/tools/rasm/lzsa-master/src/libdivsufsort/include/divsufsort_private.h new file mode 100644 index 0000000..b4d97ad --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/include/divsufsort_private.h @@ -0,0 +1,205 @@ +/* + * divsufsort_private.h for libdivsufsort + * Copyright (c) 2003-2008 Yuta Mori 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 _DIVSUFSORT_PRIVATE_H +#define _DIVSUFSORT_PRIVATE_H 1 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "divsufsort_config.h" +#include +#include +#if HAVE_STRING_H +# include +#endif +#if HAVE_STDLIB_H +# include +#endif +#if HAVE_MEMORY_H +# include +#endif +#if HAVE_STDDEF_H +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_INTTYPES_H +# include +#else +# if HAVE_STDINT_H +# include +# endif +#endif +#if defined(BUILD_DIVSUFSORT64) +# include "divsufsort64.h" +# ifndef SAIDX_T +# define SAIDX_T +# define saidx_t saidx64_t +# endif /* SAIDX_T */ +# ifndef PRIdSAIDX_T +# define PRIdSAIDX_T PRIdSAIDX64_T +# endif /* PRIdSAIDX_T */ +# define divsufsort divsufsort64 +# define divbwt divbwt64 +# define divsufsort_version divsufsort64_version +# define bw_transform bw_transform64 +# define inverse_bw_transform inverse_bw_transform64 +# define sufcheck sufcheck64 +# define sa_search sa_search64 +# define sa_simplesearch sa_simplesearch64 +# define sssort sssort64 +# define trsort trsort64 +#else +# include "divsufsort.h" +#endif + + +/*- Constants -*/ +#if !defined(UINT8_MAX) +# define UINT8_MAX (255) +#endif /* UINT8_MAX */ +#if defined(ALPHABET_SIZE) && (ALPHABET_SIZE < 1) +# undef ALPHABET_SIZE +#endif +#if !defined(ALPHABET_SIZE) +# define ALPHABET_SIZE (UINT8_MAX + 1) +#endif +/* for divsufsort.c */ +#define BUCKET_A_SIZE (ALPHABET_SIZE) +#define BUCKET_B_SIZE (ALPHABET_SIZE * ALPHABET_SIZE) +/* for sssort.c */ +#if defined(SS_INSERTIONSORT_THRESHOLD) +# if SS_INSERTIONSORT_THRESHOLD < 1 +# undef SS_INSERTIONSORT_THRESHOLD +# define SS_INSERTIONSORT_THRESHOLD (1) +# endif +#else +# define SS_INSERTIONSORT_THRESHOLD (8) +#endif +#if defined(SS_BLOCKSIZE) +# if SS_BLOCKSIZE < 0 +# undef SS_BLOCKSIZE +# define SS_BLOCKSIZE (0) +# elif 32768 <= SS_BLOCKSIZE +# undef SS_BLOCKSIZE +# define SS_BLOCKSIZE (32767) +# endif +#else +# define SS_BLOCKSIZE (1024) +#endif +/* minstacksize = log(SS_BLOCKSIZE) / log(3) * 2 */ +#if SS_BLOCKSIZE == 0 +# if defined(BUILD_DIVSUFSORT64) +# define SS_MISORT_STACKSIZE (96) +# else +# define SS_MISORT_STACKSIZE (64) +# endif +#elif SS_BLOCKSIZE <= 4096 +# define SS_MISORT_STACKSIZE (16) +#else +# define SS_MISORT_STACKSIZE (24) +#endif +#if defined(BUILD_DIVSUFSORT64) +# define SS_SMERGE_STACKSIZE (64) +#else +# define SS_SMERGE_STACKSIZE (32) +#endif +/* for trsort.c */ +#define TR_INSERTIONSORT_THRESHOLD (8) +#if defined(BUILD_DIVSUFSORT64) +# define TR_STACKSIZE (96) +#else +# define TR_STACKSIZE (64) +#endif + + +/*- Macros -*/ +#ifndef SWAP +# define SWAP(_a, _b) do { t = (_a); (_a) = (_b); (_b) = t; } while(0) +#endif /* SWAP */ +#ifndef MIN +# define MIN(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) +#endif /* MIN */ +#ifndef MAX +# define MAX(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) +#endif /* MAX */ +#define STACK_PUSH(_a, _b, _c, _d)\ + do {\ + assert(ssize < STACK_SIZE);\ + stack[ssize].a = (_a), stack[ssize].b = (_b),\ + stack[ssize].c = (_c), stack[ssize++].d = (_d);\ + } while(0) +#define STACK_PUSH5(_a, _b, _c, _d, _e)\ + do {\ + assert(ssize < STACK_SIZE);\ + stack[ssize].a = (_a), stack[ssize].b = (_b),\ + stack[ssize].c = (_c), stack[ssize].d = (_d), stack[ssize++].e = (_e);\ + } while(0) +#define STACK_POP(_a, _b, _c, _d)\ + do {\ + assert(0 <= ssize);\ + if(ssize == 0) { return; }\ + (_a) = stack[--ssize].a, (_b) = stack[ssize].b,\ + (_c) = stack[ssize].c, (_d) = stack[ssize].d;\ + } while(0) +#define STACK_POP5(_a, _b, _c, _d, _e)\ + do {\ + assert(0 <= ssize);\ + if(ssize == 0) { return; }\ + (_a) = stack[--ssize].a, (_b) = stack[ssize].b,\ + (_c) = stack[ssize].c, (_d) = stack[ssize].d, (_e) = stack[ssize].e;\ + } while(0) +/* for divsufsort.c */ +#define BUCKET_A(_c0) bucket_A[(_c0)] +#if ALPHABET_SIZE == 256 +#define BUCKET_B(_c0, _c1) (bucket_B[((_c1) << 8) | (_c0)]) +#define BUCKET_BSTAR(_c0, _c1) (bucket_B[((_c0) << 8) | (_c1)]) +#else +#define BUCKET_B(_c0, _c1) (bucket_B[(_c1) * ALPHABET_SIZE + (_c0)]) +#define BUCKET_BSTAR(_c0, _c1) (bucket_B[(_c0) * ALPHABET_SIZE + (_c1)]) +#endif + + +/*- Private Prototypes -*/ +/* sssort.c */ +void +sssort(const sauchar_t *Td, const saidx_t *PA, + saidx_t *first, saidx_t *last, + saidx_t *buf, saidx_t bufsize, + saidx_t depth, saidx_t n, saint_t lastsuffix); +/* trsort.c */ +void +trsort(saidx_t *ISA, saidx_t *SA, saidx_t n, saidx_t depth); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* _DIVSUFSORT_PRIVATE_H */ diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/include/lfs.h.cmake b/tools/rasm/lzsa-master/src/libdivsufsort/include/lfs.h.cmake new file mode 100644 index 0000000..d5b84a8 --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/include/lfs.h.cmake @@ -0,0 +1,56 @@ +/* + * lfs.h for libdivsufsort + * Copyright (c) 2003-2008 Yuta Mori 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 _LFS_H +#define _LFS_H 1 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef __STRICT_ANSI__ +# define LFS_OFF_T @LFS_OFF_T@ +# define LFS_FOPEN @LFS_FOPEN@ +# define LFS_FTELL @LFS_FTELL@ +# define LFS_FSEEK @LFS_FSEEK@ +# define LFS_PRId @LFS_PRID@ +#else +# define LFS_OFF_T long +# define LFS_FOPEN fopen +# define LFS_FTELL ftell +# define LFS_FSEEK fseek +# define LFS_PRId "ld" +#endif +#ifndef PRIdOFF_T +# define PRIdOFF_T LFS_PRId +#endif + + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* _LFS_H */ diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/pkgconfig/CMakeLists.txt b/tools/rasm/lzsa-master/src/libdivsufsort/pkgconfig/CMakeLists.txt new file mode 100644 index 0000000..ee7063c --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/pkgconfig/CMakeLists.txt @@ -0,0 +1,9 @@ +## generate libdivsufsort.pc ## +set(W64BIT "") +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/libdivsufsort.pc.cmake" "${CMAKE_CURRENT_BINARY_DIR}/libdivsufsort.pc" @ONLY) +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libdivsufsort.pc" DESTINATION ${CMAKE_INSTALL_PKGCONFIGDIR}) +if(BUILD_DIVSUFSORT64) + set(W64BIT "64") + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/libdivsufsort.pc.cmake" "${CMAKE_CURRENT_BINARY_DIR}/libdivsufsort64.pc" @ONLY) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libdivsufsort64.pc" DESTINATION ${CMAKE_INSTALL_PKGCONFIGDIR}) +endif(BUILD_DIVSUFSORT64) diff --git a/tools/rasm/lzsa-master/src/libdivsufsort/pkgconfig/libdivsufsort.pc.cmake b/tools/rasm/lzsa-master/src/libdivsufsort/pkgconfig/libdivsufsort.pc.cmake new file mode 100644 index 0000000..6419d1e --- /dev/null +++ b/tools/rasm/lzsa-master/src/libdivsufsort/pkgconfig/libdivsufsort.pc.cmake @@ -0,0 +1,11 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=@CMAKE_INSTALL_LIBDIR@ +includedir=@CMAKE_INSTALL_INCLUDEDIR@ + +Name: @PROJECT_NAME@@W64BIT@ +Description: @PROJECT_DESCRIPTION@ +Version: @PROJECT_VERSION_FULL@ +URL: @PROJECT_URL@ +Libs: -L${libdir} -ldivsufsort@W64BIT@ +Cflags: -I${includedir} diff --git a/tools/rasm/lzsa-master/src/lzsa.c b/tools/rasm/lzsa-master/src/lzsa.c new file mode 100755 index 0000000..96a460a --- /dev/null +++ b/tools/rasm/lzsa-master/src/lzsa.c @@ -0,0 +1,1109 @@ +/* + * lzsa.c - command line compression utility for the LZSA format + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#include +#include +#include +#ifdef _WIN32 +#include +#include +#else +#include +#endif +#include "lib.h" + +#define OPT_VERBOSE 1 +#define OPT_RAW 2 +#define OPT_FAVOR_RATIO 4 +#define OPT_RAW_BACKWARD 8 +#define OPT_STATS 16 + +#define TOOL_VERSION "1.3.5" + +/*---------------------------------------------------------------------------*/ + +#ifdef _WIN32 +LARGE_INTEGER hpc_frequency; +BOOL hpc_available = FALSE; +#endif + +static void do_init_time() { +#ifdef _WIN32 + hpc_frequency.QuadPart = 0; + hpc_available = QueryPerformanceFrequency(&hpc_frequency); +#endif +} + +static long long do_get_time() { + long long nTime; + +#ifdef _WIN32 + if (hpc_available) { + LARGE_INTEGER nCurTime; + + /* Use HPC hardware for best precision */ + QueryPerformanceCounter(&nCurTime); + nTime = (long long)(nCurTime.QuadPart * 1000000LL / hpc_frequency.QuadPart); + } + else { + struct _timeb tb; + _ftime(&tb); + + nTime = ((long long)tb.time * 1000LL + (long long)tb.millitm) * 1000LL; + } +#else + struct timeval tm; + gettimeofday(&tm, NULL); + + nTime = (long long)tm.tv_sec * 1000000LL + (long long)tm.tv_usec; +#endif + return nTime; +} + +/*---------------------------------------------------------------------------*/ + +static void compression_progress(long long nOriginalSize, long long nCompressedSize) { + if (nOriginalSize >= 1024 * 1024) { + fprintf(stdout, "\r%lld => %lld (%g %%) \b\b\b\b\b", nOriginalSize, nCompressedSize, (double)(nCompressedSize * 100.0 / nOriginalSize)); + fflush(stdout); + } +} + +static int do_compress(const char *pszInFilename, const char *pszOutFilename, const char *pszDictionaryFilename, const unsigned int nOptions, const int nMinMatchSize, const int nFormatVersion) { + long long nStartTime = 0LL, nEndTime = 0LL; + long long nOriginalSize = 0LL, nCompressedSize = 0LL; + int nCommandCount = 0, nSafeDist = 0; + int nFlags; + lzsa_status_t nStatus; + lzsa_stats stats; + + nFlags = 0; + if (nOptions & OPT_FAVOR_RATIO) + nFlags |= LZSA_FLAG_FAVOR_RATIO; + if (nOptions & OPT_RAW) + nFlags |= LZSA_FLAG_RAW_BLOCK; + if (nOptions & OPT_RAW_BACKWARD) + nFlags |= LZSA_FLAG_RAW_BACKWARD; + + if (nOptions & OPT_VERBOSE) { + nStartTime = do_get_time(); + } + + nStatus = lzsa_compress_file(pszInFilename, pszOutFilename, pszDictionaryFilename, nFlags, nMinMatchSize, nFormatVersion, compression_progress, &nOriginalSize, &nCompressedSize, &nCommandCount, &nSafeDist, &stats); + + if ((nOptions & OPT_VERBOSE)) { + nEndTime = do_get_time(); + } + + switch (nStatus) { + case LZSA_ERROR_SRC: fprintf(stderr, "error reading '%s'\n", pszInFilename); break; + case LZSA_ERROR_DST: fprintf(stderr, "error writing '%s'\n", pszOutFilename); break; + case LZSA_ERROR_DICTIONARY: fprintf(stderr, "error reading dictionary '%s'\n", pszDictionaryFilename); break; + case LZSA_ERROR_MEMORY: fprintf(stderr, "out of memory\n"); break; + case LZSA_ERROR_COMPRESSION: fprintf(stderr, "internal compression error\n"); break; + case LZSA_ERROR_RAW_TOOLARGE: fprintf(stderr, "error: raw blocks can only be used with files <= 64 Kb\n"); break; + case LZSA_ERROR_RAW_UNCOMPRESSED: fprintf(stderr, "error: incompressible data needs to be <= 64 Kb in raw blocks\n"); break; + case LZSA_OK: break; + default: fprintf(stderr, "unknown compression error %d\n", nStatus); break; + } + + if (nStatus) + return 100; + + if ((nOptions & OPT_VERBOSE)) { + double fDelta = ((double)(nEndTime - nStartTime)) / 1000000.0; + double fSpeed = ((double)nOriginalSize / 1048576.0) / fDelta; + fprintf(stdout, "\rCompressed '%s' in %g seconds, %.02g Mb/s, %d tokens (%g bytes/token), %lld into %lld bytes ==> %g %%\n", + pszInFilename, fDelta, fSpeed, nCommandCount, (double)nOriginalSize / (double)nCommandCount, + nOriginalSize, nCompressedSize, (double)(nCompressedSize * 100.0 / nOriginalSize)); + if (nOptions & OPT_RAW) { + fprintf(stdout, "Safe distance: %d (0x%X)\n", nSafeDist, nSafeDist); + } + } + + if (nOptions & OPT_STATS) { + if (stats.literals_divisor > 0) + fprintf(stdout, "Literals: min: %d avg: %d max: %d count: %d\n", stats.min_literals, stats.total_literals / stats.literals_divisor, stats.max_literals, stats.literals_divisor); + else + fprintf(stdout, "Literals: none\n"); + if (stats.match_divisor > 0) { + fprintf(stdout, "Offsets: min: %d avg: %d max: %d reps: %d count: %d\n", stats.min_offset, stats.total_offsets / stats.match_divisor, stats.max_offset, stats.num_rep_offsets, stats.match_divisor); + fprintf(stdout, "Match lens: min: %d avg: %d max: %d count: %d\n", stats.min_match_len, stats.total_match_lens / stats.match_divisor, stats.max_match_len, stats.match_divisor); + } + else { + fprintf(stdout, "Offsets: none\n"); + fprintf(stdout, "Match lens: none\n"); + } + if (stats.rle1_divisor > 0) { + fprintf(stdout, "RLE1 lens: min: %d avg: %d max: %d count: %d\n", stats.min_rle1_len, stats.total_rle1_lens / stats.rle1_divisor, stats.max_rle1_len, stats.rle1_divisor); + } + else { + fprintf(stdout, "RLE1 lens: none\n"); + } + if (stats.rle2_divisor > 0) { + fprintf(stdout, "RLE2 lens: min: %d avg: %d max: %d count: %d\n", stats.min_rle2_len, stats.total_rle2_lens / stats.rle2_divisor, stats.max_rle2_len, stats.rle2_divisor); + } + else { + fprintf(stdout, "RLE2 lens: none\n"); + } + } + return 0; +} + +/*---------------------------------------------------------------------------*/ + +static int do_decompress(const char *pszInFilename, const char *pszOutFilename, const char *pszDictionaryFilename, const unsigned int nOptions, int nFormatVersion) { + long long nStartTime = 0LL, nEndTime = 0LL; + long long nOriginalSize = 0LL, nCompressedSize = 0LL; + lzsa_status_t nStatus; + int nFlags; + + nFlags = 0; + if (nOptions & OPT_RAW) + nFlags |= LZSA_FLAG_RAW_BLOCK; + if (nOptions & OPT_RAW_BACKWARD) + nFlags |= LZSA_FLAG_RAW_BACKWARD; + + if (nOptions & OPT_VERBOSE) { + nStartTime = do_get_time(); + } + + nStatus = lzsa_decompress_file(pszInFilename, pszOutFilename, pszDictionaryFilename, nFlags, nFormatVersion, &nOriginalSize, &nCompressedSize); + + switch (nStatus) { + case LZSA_ERROR_SRC: fprintf(stderr, "error reading '%s'\n", pszInFilename); break; + case LZSA_ERROR_DST: fprintf(stderr, "error writing '%s'\n", pszOutFilename); break; + case LZSA_ERROR_DICTIONARY: fprintf(stderr, "error reading dictionary '%s'\n", pszDictionaryFilename); break; + case LZSA_ERROR_MEMORY: fprintf(stderr, "out of memory\n"); break; + case LZSA_ERROR_DECOMPRESSION: fprintf(stderr, "internal decompression error\n"); break; + case LZSA_ERROR_FORMAT: fprintf(stderr, "invalid magic number or format version in input file\n"); break; + case LZSA_OK: break; + default: fprintf(stderr, "unknown decompression error %d\n", nStatus); break; + } + + if (nStatus) { + fprintf(stderr, "decompression error for '%s'\n", pszInFilename); + return 100; + } + else { + if (nOptions & OPT_VERBOSE) { + nEndTime = do_get_time(); + double fDelta = ((double)(nEndTime - nStartTime)) / 1000000.0; + double fSpeed = ((double)nOriginalSize / 1048576.0) / fDelta; + fprintf(stdout, "Decompressed '%s' in %g seconds, %g Mb/s\n", + pszInFilename, fDelta, fSpeed); + } + + return 0; + } +} + +/*---------------------------------------------------------------------------*/ + +typedef struct { + FILE *f; + void *pCompareDataBuf; + size_t nCompareDataSize; +} compare_stream_t; + +void comparestream_close(lzsa_stream_t *stream) { + if (stream->obj) { + compare_stream_t *pCompareStream = (compare_stream_t *)stream->obj; + if (pCompareStream->pCompareDataBuf) { + free(pCompareStream->pCompareDataBuf); + pCompareStream->pCompareDataBuf = NULL; + } + + fclose(pCompareStream->f); + free(pCompareStream); + + stream->obj = NULL; + stream->read = NULL; + stream->write = NULL; + stream->eof = NULL; + stream->close = NULL; + } +} + +size_t comparestream_read(lzsa_stream_t *stream, void *ptr, size_t size) { + return 0; +} + +size_t comparestream_write(lzsa_stream_t *stream, void *ptr, size_t size) { + compare_stream_t *pCompareStream = (compare_stream_t *)stream->obj; + + if (!pCompareStream->pCompareDataBuf || pCompareStream->nCompareDataSize < size) { + pCompareStream->nCompareDataSize = size; + pCompareStream->pCompareDataBuf = realloc(pCompareStream->pCompareDataBuf, pCompareStream->nCompareDataSize); + if (!pCompareStream->pCompareDataBuf) + return 0; + } + + size_t nReadBytes = fread(pCompareStream->pCompareDataBuf, 1, size, pCompareStream->f); + if (nReadBytes != size) { + return 0; + } + + if (memcmp(ptr, pCompareStream->pCompareDataBuf, size)) { + return 0; + } + + return size; +} + +int comparestream_eof(lzsa_stream_t *stream) { + compare_stream_t *pCompareStream = (compare_stream_t *)stream->obj; + return feof(pCompareStream->f); +} + +int comparestream_open(lzsa_stream_t *stream, const char *pszCompareFilename, const char *pszMode) { + compare_stream_t *pCompareStream; + + pCompareStream = (compare_stream_t*)malloc(sizeof(compare_stream_t)); + if (!pCompareStream) + return -1; + + pCompareStream->pCompareDataBuf = NULL; + pCompareStream->nCompareDataSize = 0; + pCompareStream->f = (FILE*)fopen(pszCompareFilename, pszMode); + + if (pCompareStream->f) { + stream->obj = pCompareStream; + stream->read = comparestream_read; + stream->write = comparestream_write; + stream->eof = comparestream_eof; + stream->close = comparestream_close; + return 0; + } + else { + free(pCompareStream); + return -1; + } +} + +static int do_compare(const char *pszInFilename, const char *pszOutFilename, const char *pszDictionaryFilename, const unsigned int nOptions, int nFormatVersion) { + lzsa_stream_t inStream, compareStream; + long long nStartTime = 0LL, nEndTime = 0LL; + long long nOriginalSize = 0LL; + long long nCompressedSize = 0LL; + void *pDictionaryData = NULL; + int nDictionaryDataSize = 0; + lzsa_status_t nStatus; + int nFlags; + + if (lzsa_filestream_open(&inStream, pszInFilename, "rb") < 0) { + fprintf(stderr, "error opening compressed input file\n"); + return 100; + } + + if (comparestream_open(&compareStream, pszOutFilename, "rb") < 0) { + fprintf(stderr, "error opening original uncompressed file\n"); + inStream.close(&inStream); + return 100; + } + + nStatus = lzsa_dictionary_load(pszDictionaryFilename, &pDictionaryData, &nDictionaryDataSize); + if (nStatus) { + compareStream.close(&compareStream); + inStream.close(&inStream); + fprintf(stderr, "error reading dictionary '%s'\n", pszDictionaryFilename); + return 100; + } + + nFlags = 0; + if (nOptions & OPT_RAW) + nFlags |= LZSA_FLAG_RAW_BLOCK; + if (nOptions & OPT_RAW_BACKWARD) + nFlags |= LZSA_FLAG_RAW_BACKWARD; + + if (nOptions & OPT_VERBOSE) { + nStartTime = do_get_time(); + } + + nStatus = lzsa_decompress_stream(&inStream, &compareStream, pDictionaryData, nDictionaryDataSize, nFlags, nFormatVersion, &nOriginalSize, &nCompressedSize); + + switch (nStatus) { + case LZSA_ERROR_SRC: fprintf(stderr, "error reading '%s'\n", pszInFilename); break; + case LZSA_ERROR_DST: fprintf(stderr, "error comparing compressed file '%s' with original '%s'\n", pszInFilename, pszOutFilename); break; + case LZSA_ERROR_MEMORY: fprintf(stderr, "out of memory\n"); break; + case LZSA_ERROR_DECOMPRESSION: fprintf(stderr, "internal decompression error\n"); break; + case LZSA_ERROR_FORMAT: fprintf(stderr, "invalid magic number or format version in input file\n"); break; + case LZSA_OK: break; + default: fprintf(stderr, "unknown decompression error %d\n", nStatus); break; + } + + lzsa_dictionary_free(&pDictionaryData); + compareStream.close(&compareStream); + inStream.close(&inStream); + + if (nStatus) { + return 100; + } + else { + if (nOptions & OPT_VERBOSE) { + nEndTime = do_get_time(); + double fDelta = ((double)(nEndTime - nStartTime)) / 1000000.0; + double fSpeed = ((double)nOriginalSize / 1048576.0) / fDelta; + fprintf(stdout, "Compared '%s' in %g seconds, %g Mb/s\n", + pszInFilename, fDelta, fSpeed); + } + + return 0; + } +} + +/*---------------------------------------------------------------------------*/ + +static void generate_compressible_data(unsigned char *pBuffer, size_t nBufferSize, int nMinMatchSize, unsigned int nSeed, int nNumLiteralValues, float fMatchProbability) { + size_t nIndex = 0; + int nMatchProbability = (int)(fMatchProbability * 1023.0f); + + srand(nSeed); + + if (nIndex >= nBufferSize) return; + pBuffer[nIndex++] = rand() % nNumLiteralValues; + + while (nIndex < nBufferSize) { + if ((rand() & 1023) >= nMatchProbability) { + size_t nLiteralCount = rand() & 127; + if (nLiteralCount > (nBufferSize - nIndex)) + nLiteralCount = nBufferSize - nIndex; + + while (nLiteralCount--) + pBuffer[nIndex++] = rand() % nNumLiteralValues; + } + else { + size_t nMatchLength = nMinMatchSize + (rand() & 1023); + size_t nMatchOffset; + + if (nMatchLength > (nBufferSize - nIndex)) + nMatchLength = nBufferSize - nIndex; + if (nMatchLength > nIndex) + nMatchLength = nIndex; + + if (nMatchLength < nIndex) + nMatchOffset = rand() % (nIndex - nMatchLength); + else + nMatchOffset = 0; + + while (nMatchLength--) { + pBuffer[nIndex] = pBuffer[nIndex - nMatchOffset]; + nIndex++; + } + } + } +} + +static void xor_data(unsigned char *pBuffer, size_t nBufferSize, unsigned int nSeed, float fXorProbability) { + size_t nIndex = 0; + int nXorProbability = (int)(fXorProbability * 1023.0f); + + srand(nSeed); + + if (nIndex >= nBufferSize) return; + + while (nIndex < nBufferSize) { + if ((rand() & 1023) < nXorProbability) { + pBuffer[nIndex] ^= 0xff; + } + nIndex++; + } +} + +static int do_self_test(const unsigned int nOptions, const int nMinMatchSize, int nFormatVersion) { + unsigned char *pGeneratedData; + unsigned char *pCompressedData; + unsigned char *pTmpCompressedData; + unsigned char *pTmpDecompressedData; + size_t nGeneratedDataSize; + size_t nMaxCompressedDataSize; + unsigned int nSeed = 123; + int nFlags; + int i; + + nFlags = 0; + if (nOptions & OPT_FAVOR_RATIO) + nFlags |= LZSA_FLAG_FAVOR_RATIO; + if (nOptions & OPT_RAW) + nFlags |= LZSA_FLAG_RAW_BLOCK; + if (nOptions & OPT_RAW_BACKWARD) + nFlags |= LZSA_FLAG_RAW_BACKWARD; + + pGeneratedData = (unsigned char*)malloc(4 * BLOCK_SIZE); + if (!pGeneratedData) { + fprintf(stderr, "out of memory, %d bytes needed\n", 4 * BLOCK_SIZE); + return 100; + } + + nMaxCompressedDataSize = lzsa_get_max_compressed_size_inmem(4 * BLOCK_SIZE); + pCompressedData = (unsigned char*)malloc(nMaxCompressedDataSize); + if (!pCompressedData) { + free(pGeneratedData); + pGeneratedData = NULL; + + fprintf(stderr, "out of memory, %zd bytes needed\n", nMaxCompressedDataSize); + return 100; + } + + pTmpCompressedData = (unsigned char*)malloc(nMaxCompressedDataSize); + if (!pTmpCompressedData) { + free(pCompressedData); + pCompressedData = NULL; + free(pGeneratedData); + pGeneratedData = NULL; + + fprintf(stderr, "out of memory, %zd bytes needed\n", nMaxCompressedDataSize); + return 100; + } + + pTmpDecompressedData = (unsigned char*)malloc(4 * BLOCK_SIZE); + if (!pTmpDecompressedData) { + free(pTmpCompressedData); + pTmpCompressedData = NULL; + free(pCompressedData); + pCompressedData = NULL; + free(pGeneratedData); + pGeneratedData = NULL; + + fprintf(stderr, "out of memory, %d bytes needed\n", 4 * BLOCK_SIZE); + return 100; + } + + memset(pGeneratedData, 0, 4 * BLOCK_SIZE); + memset(pCompressedData, 0, nMaxCompressedDataSize); + memset(pTmpCompressedData, 0, nMaxCompressedDataSize); + + /* Test compressing with a too small buffer to do anything, expect to fail cleanly */ + for (i = 0; i < 12; i++) { + generate_compressible_data(pGeneratedData, i, nMinMatchSize, nSeed, 256, 0.5f); + lzsa_compress_inmem(pGeneratedData, pCompressedData, i, i, nFlags, nMinMatchSize, nFormatVersion); + } + + size_t nDataSizeStep = 128; + float fProbabilitySizeStep = 0.0005f; + + for (nGeneratedDataSize = 1024; nGeneratedDataSize <= ((size_t)((nOptions & OPT_RAW) ? BLOCK_SIZE : (4 * BLOCK_SIZE))); nGeneratedDataSize += nDataSizeStep) { + float fMatchProbability; + + fprintf(stdout, "size %zd", nGeneratedDataSize); + for (fMatchProbability = 0; fMatchProbability <= 0.995f; fMatchProbability += fProbabilitySizeStep) { + int nNumLiteralValues[12] = { 1, 2, 3, 15, 30, 56, 96, 137, 178, 191, 255, 256 }; + float fXorProbability; + + fputc('.', stdout); + fflush(stdout); + + for (i = 0; i < 12; i++) { + /* Generate data to compress */ + generate_compressible_data(pGeneratedData, nGeneratedDataSize, nMinMatchSize, nSeed, nNumLiteralValues[i], fMatchProbability); + + /* Try to compress it, expected to succeed */ + size_t nActualCompressedSize = lzsa_compress_inmem(pGeneratedData, pCompressedData, nGeneratedDataSize, lzsa_get_max_compressed_size_inmem(nGeneratedDataSize), + nFlags, nMinMatchSize, nFormatVersion); + if (nActualCompressedSize == -1 || (int)nActualCompressedSize < (lzsa_get_header_size() + lzsa_get_frame_size() + lzsa_get_frame_size() /* footer */)) { + free(pTmpDecompressedData); + pTmpDecompressedData = NULL; + free(pTmpCompressedData); + pTmpCompressedData = NULL; + free(pCompressedData); + pCompressedData = NULL; + free(pGeneratedData); + pGeneratedData = NULL; + + fprintf(stderr, "\nself-test: error compressing size %zd, seed %d, match probability %f, literals range %d\n", nGeneratedDataSize, nSeed, fMatchProbability, nNumLiteralValues[i]); + return 100; + } + + /* Try to decompress it, expected to succeed */ + size_t nActualDecompressedSize; + int nDecFormatVersion = nFormatVersion; + nActualDecompressedSize = lzsa_decompress_inmem(pCompressedData, pTmpDecompressedData, nActualCompressedSize, nGeneratedDataSize, nFlags, &nDecFormatVersion); + if (nActualDecompressedSize == -1) { + free(pTmpDecompressedData); + pTmpDecompressedData = NULL; + free(pTmpCompressedData); + pTmpCompressedData = NULL; + free(pCompressedData); + pCompressedData = NULL; + free(pGeneratedData); + pGeneratedData = NULL; + + fprintf(stderr, "\nself-test: error decompressing size %zd, seed %d, match probability %f, literals range %d\n", nGeneratedDataSize, nSeed, fMatchProbability, nNumLiteralValues[i]); + return 100; + } + + if (memcmp(pGeneratedData, pTmpDecompressedData, nGeneratedDataSize)) { + free(pTmpDecompressedData); + pTmpDecompressedData = NULL; + free(pTmpCompressedData); + pTmpCompressedData = NULL; + free(pCompressedData); + pCompressedData = NULL; + free(pGeneratedData); + pGeneratedData = NULL; + + fprintf(stderr, "\nself-test: error comparing decompressed and original data, size %zd, seed %d, match probability %f, literals range %d\n", nGeneratedDataSize, nSeed, fMatchProbability, nNumLiteralValues[i]); + return 100; + } + + /* Try to decompress corrupted data, expected to fail cleanly, without crashing or corrupting memory outside the output buffer */ + for (fXorProbability = 0.05f; fXorProbability <= 0.5f; fXorProbability += 0.05f) { + memcpy(pTmpCompressedData, pCompressedData, nActualCompressedSize); + xor_data(pTmpCompressedData + lzsa_get_header_size() + lzsa_get_frame_size(), nActualCompressedSize - lzsa_get_header_size() - lzsa_get_frame_size() - lzsa_get_frame_size() /* footer */, nSeed, fXorProbability); + nDecFormatVersion = nFormatVersion; + lzsa_decompress_inmem(pTmpCompressedData, pGeneratedData, nActualCompressedSize, nGeneratedDataSize, nFlags, &nDecFormatVersion); + } + } + + nSeed++; + } + + fputc(10, stdout); + fflush(stdout); + + nDataSizeStep <<= 1; + if (nDataSizeStep > (128 * 4096)) + nDataSizeStep = 128 * 4096; + fProbabilitySizeStep *= 1.25; + if (fProbabilitySizeStep > (0.0005f * 4096)) + fProbabilitySizeStep = 0.0005f * 4096; + } + + free(pTmpDecompressedData); + pTmpDecompressedData = NULL; + + free(pTmpCompressedData); + pTmpCompressedData = NULL; + + free(pCompressedData); + pCompressedData = NULL; + + free(pGeneratedData); + pGeneratedData = NULL; + + fprintf(stdout, "All tests passed.\n"); + return 0; +} + +/*---------------------------------------------------------------------------*/ + +static int do_compr_benchmark(const char *pszInFilename, const char *pszOutFilename, const char *pszDictionaryFilename, const unsigned int nOptions, const int nMinMatchSize, int nFormatVersion) { + size_t nFileSize, nMaxCompressedSize; + unsigned char *pFileData; + unsigned char *pCompressedData; + int nFlags; + int i; + + nFlags = 0; + if (nOptions & OPT_FAVOR_RATIO) + nFlags |= LZSA_FLAG_FAVOR_RATIO; + if (nOptions & OPT_RAW) + nFlags |= LZSA_FLAG_RAW_BLOCK; + if (nOptions & OPT_RAW_BACKWARD) + nFlags |= LZSA_FLAG_RAW_BACKWARD; + + if (pszDictionaryFilename) { + fprintf(stderr, "in-memory benchmarking does not support dictionaries\n"); + return 100; + } + + /* Read the whole original file in memory */ + + FILE *f_in = fopen(pszInFilename, "rb"); + if (!f_in) { + fprintf(stderr, "error opening '%s' for reading\n", pszInFilename); + return 100; + } + + fseek(f_in, 0, SEEK_END); + nFileSize = (size_t)ftell(f_in); + fseek(f_in, 0, SEEK_SET); + + pFileData = (unsigned char*)malloc(nFileSize); + if (!pFileData) { + fclose(f_in); + fprintf(stderr, "out of memory for reading '%s', %zd bytes needed\n", pszInFilename, nFileSize); + return 100; + } + + if (fread(pFileData, 1, nFileSize, f_in) != nFileSize) { + free(pFileData); + fclose(f_in); + fprintf(stderr, "I/O error while reading '%s'\n", pszInFilename); + return 100; + } + + fclose(f_in); + + /* Allocate max compressed size */ + + nMaxCompressedSize = lzsa_get_max_compressed_size_inmem(nFileSize); + + pCompressedData = (unsigned char*)malloc(nMaxCompressedSize + 2048); + if (!pCompressedData) { + free(pFileData); + fprintf(stderr, "out of memory for compressing '%s', %zd bytes needed\n", pszInFilename, nMaxCompressedSize); + return 100; + } + + memset(pCompressedData + 1024, 0, nMaxCompressedSize); + + long long nBestCompTime = -1; + + size_t nActualCompressedSize = 0; + size_t nRightGuardPos = nMaxCompressedSize; + + for (i = 0; i < 5; i++) { + unsigned char nGuard = 0x33 + i; + int j; + + /* Write guard bytes around the output buffer, to help check for writes outside of it by the compressor */ + memset(pCompressedData, nGuard, 1024); + memset(pCompressedData + 1024 + nRightGuardPos, nGuard, 1024); + + long long t0 = do_get_time(); + nActualCompressedSize = lzsa_compress_inmem(pFileData, pCompressedData + 1024, nFileSize, nRightGuardPos, nFlags, nMinMatchSize, nFormatVersion); + long long t1 = do_get_time(); + if (nActualCompressedSize == -1) { + free(pCompressedData); + free(pFileData); + fprintf(stderr, "compression error\n"); + return 100; + } + + long long nCurDecTime = t1 - t0; + if (nBestCompTime == -1 || nBestCompTime > nCurDecTime) + nBestCompTime = nCurDecTime; + + /* Check guard bytes before the output buffer */ + for (j = 0; j < 1024; j++) { + if (pCompressedData[j] != nGuard) { + free(pCompressedData); + free(pFileData); + fprintf(stderr, "error, wrote outside of output buffer at %d!\n", j - 1024); + return 100; + } + } + + /* Check guard bytes after the output buffer */ + for (j = 0; j < 1024; j++) { + if (pCompressedData[1024 + nRightGuardPos + j] != nGuard) { + free(pCompressedData); + free(pFileData); + fprintf(stderr, "error, wrote outside of output buffer at %d!\n", j); + return 100; + } + } + + nRightGuardPos = nActualCompressedSize; + } + + if (pszOutFilename) { + FILE *f_out; + + /* Write whole compressed file out */ + + f_out = fopen(pszOutFilename, "wb"); + if (f_out) { + fwrite(pCompressedData + 1024, 1, nActualCompressedSize, f_out); + fclose(f_out); + } + } + + free(pCompressedData); + free(pFileData); + + fprintf(stdout, "compressed size: %zd bytes\n", nActualCompressedSize); + fprintf(stdout, "compression time: %lld microseconds (%g Mb/s)\n", nBestCompTime, ((double)nActualCompressedSize / 1024.0) / ((double)nBestCompTime / 1000.0)); + + return 0; +} + +/*---------------------------------------------------------------------------*/ + +static int do_dec_benchmark(const char *pszInFilename, const char *pszOutFilename, const char *pszDictionaryFilename, const unsigned int nOptions, int nFormatVersion) { + size_t nFileSize, nMaxDecompressedSize; + unsigned char *pFileData; + unsigned char *pDecompressedData; + int nFlags; + int i; + + nFlags = 0; + if (nOptions & OPT_RAW) + nFlags |= LZSA_FLAG_RAW_BLOCK; + if (nOptions & OPT_RAW_BACKWARD) + nFlags |= LZSA_FLAG_RAW_BACKWARD; + + if (pszDictionaryFilename) { + fprintf(stderr, "in-memory benchmarking does not support dictionaries\n"); + return 100; + } + + /* Read the whole compressed file in memory */ + + FILE *f_in = fopen(pszInFilename, "rb"); + if (!f_in) { + fprintf(stderr, "error opening '%s' for reading\n", pszInFilename); + return 100; + } + + fseek(f_in, 0, SEEK_END); + nFileSize = (size_t)ftell(f_in); + fseek(f_in, 0, SEEK_SET); + + pFileData = (unsigned char*)malloc(nFileSize); + if (!pFileData) { + fclose(f_in); + fprintf(stderr, "out of memory for reading '%s', %zd bytes needed\n", pszInFilename, nFileSize); + return 100; + } + + if (fread(pFileData, 1, nFileSize, f_in) != nFileSize) { + free(pFileData); + fclose(f_in); + fprintf(stderr, "I/O error while reading '%s'\n", pszInFilename); + return 100; + } + + fclose(f_in); + + /* Allocate max decompressed size */ + + if (nOptions & OPT_RAW) + nMaxDecompressedSize = 65536; + else + nMaxDecompressedSize = lzsa_get_max_decompressed_size_inmem(pFileData, nFileSize); + if (nMaxDecompressedSize == -1) { + free(pFileData); + fprintf(stderr, "invalid compressed format for file '%s'\n", pszInFilename); + return 100; + } + + pDecompressedData = (unsigned char*)malloc(nMaxDecompressedSize); + if (!pDecompressedData) { + free(pFileData); + fprintf(stderr, "out of memory for decompressing '%s', %zd bytes needed\n", pszInFilename, nMaxDecompressedSize); + return 100; + } + + memset(pDecompressedData, 0, nMaxDecompressedSize); + + long long nBestDecTime = -1; + + size_t nActualDecompressedSize = 0; + for (i = 0; i < 50; i++) { + long long t0 = do_get_time(); + nActualDecompressedSize = lzsa_decompress_inmem(pFileData, pDecompressedData, nFileSize, nMaxDecompressedSize, nFlags, &nFormatVersion); + long long t1 = do_get_time(); + if (nActualDecompressedSize == -1) { + free(pDecompressedData); + free(pFileData); + fprintf(stderr, "decompression error\n"); + return 100; + } + + long long nCurDecTime = t1 - t0; + if (nBestDecTime == -1 || nBestDecTime > nCurDecTime) + nBestDecTime = nCurDecTime; + } + + if (pszOutFilename) { + FILE *f_out; + + /* Write whole decompressed file out */ + + f_out = fopen(pszOutFilename, "wb"); + if (f_out) { + fwrite(pDecompressedData, 1, nActualDecompressedSize, f_out); + fclose(f_out); + } + } + + free(pDecompressedData); + free(pFileData); + + fprintf(stdout, "format: LZSA%d\n", nFormatVersion); + fprintf(stdout, "decompressed size: %zd bytes\n", nActualDecompressedSize); + fprintf(stdout, "decompression time: %lld microseconds (%g Mb/s)\n", nBestDecTime, ((double)nActualDecompressedSize / 1024.0) / ((double)nBestDecTime / 1000.0)); + + return 0; +} + +/*---------------------------------------------------------------------------*/ + +int main(int argc, char **argv) { + int i; + const char *pszInFilename = NULL; + const char *pszOutFilename = NULL; + const char *pszDictionaryFilename = NULL; + int nArgsError = 0; + int nCommandDefined = 0; + int nVerifyCompression = 0; + int nMinMatchDefined = 0; + int nFormatVersionDefined = 0; + char cCommand = 'z'; + int nMinMatchSize = 0; + unsigned int nOptions = OPT_FAVOR_RATIO; + int nFormatVersion = 1; + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-d")) { + if (!nCommandDefined) { + nCommandDefined = 1; + cCommand = 'd'; + } + else + nArgsError = 1; + } + else if (!strcmp(argv[i], "-z")) { + if (!nCommandDefined) { + nCommandDefined = 1; + cCommand = 'z'; + } + else + nArgsError = 1; + } + else if (!strcmp(argv[i], "-c")) { + if (!nVerifyCompression) { + nVerifyCompression = 1; + } + else + nArgsError = 1; + } + else if (!strcmp(argv[i], "-cbench")) { + if (!nCommandDefined) { + nCommandDefined = 1; + cCommand = 'B'; + } + else + nArgsError = 1; + } + else if (!strcmp(argv[i], "-dbench")) { + if (!nCommandDefined) { + nCommandDefined = 1; + cCommand = 'b'; + } + else + nArgsError = 1; + } + else if (!strcmp(argv[i], "-test")) { + if (!nCommandDefined) { + nCommandDefined = 1; + cCommand = 't'; + } + else + nArgsError = 1; + } + else if (!strcmp(argv[i], "-D")) { + if (!pszDictionaryFilename && (i + 1) < argc) { + pszDictionaryFilename = argv[i + 1]; + i++; + } + else + nArgsError = 1; + } + else if (!strncmp(argv[i], "-D", 2)) { + if (!pszDictionaryFilename) { + pszDictionaryFilename = argv[i] + 2; + } + else + nArgsError = 1; + } + else if (!strcmp(argv[i], "-m")) { + if (!nMinMatchDefined && (i + 1) < argc) { + char *pEnd = NULL; + nMinMatchSize = (int)strtol(argv[i + 1], &pEnd, 10); + if (pEnd && pEnd != argv[i + 1] && (nMinMatchSize >= 2 && nMinMatchSize <= 5)) { + i++; + nMinMatchDefined = 1; + nOptions &= (~OPT_FAVOR_RATIO); + } + else { + nArgsError = 1; + } + } + else + nArgsError = 1; + } + else if (!strncmp(argv[i], "-m", 2)) { + if (!nMinMatchDefined) { + char *pEnd = NULL; + nMinMatchSize = (int)strtol(argv[i] + 2, &pEnd, 10); + if (pEnd && pEnd != (argv[i]+2) && (nMinMatchSize >= 2 && nMinMatchSize <= 5)) { + nMinMatchDefined = 1; + nOptions &= (~OPT_FAVOR_RATIO); + } + else { + nArgsError = 1; + } + } + else + nArgsError = 1; + } + else if (!strcmp(argv[i], "--prefer-ratio")) { + if (!nMinMatchDefined) { + nMinMatchSize = 0; + nMinMatchDefined = 1; + } + else + nArgsError = 1; + } + else if (!strcmp(argv[i], "--prefer-speed")) { + if (!nMinMatchDefined) { + nMinMatchSize = 3; + nOptions &= (~OPT_FAVOR_RATIO); + nMinMatchDefined = 1; + } + else + nArgsError = 1; + } + else if (!strcmp(argv[i], "-f")) { + if (!nFormatVersionDefined && (i + 1) < argc) { + char *pEnd = NULL; + nFormatVersion = (int)strtol(argv[i + 1], &pEnd, 10); + if (pEnd && pEnd != argv[i + 1] && (nFormatVersion >= 1 && nFormatVersion <= 2)) { + i++; + nFormatVersionDefined = 1; + } + else { + nArgsError = 1; + } + } + else + nArgsError = 1; + } + else if (!strncmp(argv[i], "-f", 2)) { + if (!nFormatVersionDefined) { + char *pEnd = NULL; + nFormatVersion = (int)strtol(argv[i] + 2, &pEnd, 10); + if (pEnd && pEnd != (argv[i] + 2) && (nFormatVersion >= 1 && nFormatVersion <= 2)) { + nFormatVersionDefined = 1; + } + else { + nArgsError = 1; + } + } + else + nArgsError = 1; + } + else if (!strcmp(argv[i], "-v")) { + if ((nOptions & OPT_VERBOSE) == 0) { + nOptions |= OPT_VERBOSE; + } + else + nArgsError = 1; + } + else if (!strcmp(argv[i], "-r")) { + if ((nOptions & OPT_RAW) == 0) { + nOptions |= OPT_RAW; + } + else + nArgsError = 1; + } + else if (!strcmp(argv[i], "-b")) { + if ((nOptions & OPT_RAW_BACKWARD) == 0) { + nOptions |= OPT_RAW_BACKWARD; + } + else + nArgsError = 1; + } + else if (!strcmp(argv[i], "-stats")) { + if ((nOptions & OPT_STATS) == 0) { + nOptions |= OPT_STATS; + } + else + nArgsError = 1; + } + else { + if (!pszInFilename) + pszInFilename = argv[i]; + else { + if (!pszOutFilename) + pszOutFilename = argv[i]; + else + nArgsError = 1; + } + } + } + + if (!nArgsError && (nOptions & OPT_RAW_BACKWARD) && !(nOptions & OPT_RAW)) { + fprintf(stderr, "error: -b (compress backwards) requires -r (raw block format)\n"); + return 100; + } + + if (!nArgsError && cCommand == 't') { + return do_self_test(nOptions, nMinMatchSize, nFormatVersion); + } + + if (nArgsError || !pszInFilename || !pszOutFilename) { + fprintf(stderr, "lzsa command-line tool v" TOOL_VERSION " by Emmanuel Marty and spke\n"); + fprintf(stderr, "usage: %s [-c] [-d] [-v] [-r] \n", argv[0]); + fprintf(stderr, " -c: check resulting stream after compressing\n"); + fprintf(stderr, " -d: decompress (default: compress)\n"); + fprintf(stderr, " -cbench: benchmark in-memory compression\n"); + fprintf(stderr, " -dbench: benchmark in-memory decompression\n"); + fprintf(stderr, " -test: run automated self-tests\n"); + fprintf(stderr, " -stats: show compressed data stats\n"); + fprintf(stderr, " -v: be verbose\n"); + fprintf(stderr, " -f : LZSA compression format (1-2)\n"); + fprintf(stderr, " -r: raw block format (max. 64 Kb files)\n"); + fprintf(stderr, " -b: compress backward (requires -r and a backward decompressor)\n"); + fprintf(stderr, " -D : use dictionary file\n"); + fprintf(stderr, " -m : minimum match size (3-5) (default: 3)\n"); + fprintf(stderr, " --prefer-ratio: favor compression ratio (default)\n"); + fprintf(stderr, " --prefer-speed: favor decompression speed (same as -m3)\n"); + return 100; + } + + do_init_time(); + + if (cCommand == 'z') { + int nResult = do_compress(pszInFilename, pszOutFilename, pszDictionaryFilename, nOptions, nMinMatchSize, nFormatVersion); + if (nResult == 0 && nVerifyCompression) { + return do_compare(pszOutFilename, pszInFilename, pszDictionaryFilename, nOptions, nFormatVersion); + } else { + return nResult; + } + } + else if (cCommand == 'd') { + return do_decompress(pszInFilename, pszOutFilename, pszDictionaryFilename, nOptions, nFormatVersion); + } + else if (cCommand == 'B') { + return do_compr_benchmark(pszInFilename, pszOutFilename, pszDictionaryFilename, nOptions, nMinMatchSize, nFormatVersion); + } + else if (cCommand == 'b') { + return do_dec_benchmark(pszInFilename, pszOutFilename, pszDictionaryFilename, nOptions, nFormatVersion); + } + else { + return 100; + } +} diff --git a/tools/rasm/lzsa-master/src/matchfinder.c b/tools/rasm/lzsa-master/src/matchfinder.c new file mode 100644 index 0000000..3de2cfa --- /dev/null +++ b/tools/rasm/lzsa-master/src/matchfinder.c @@ -0,0 +1,361 @@ +/* + * matchfinder.c - LZ match finder implementation + * + * The following copying information applies to this specific source code file: + * + * Written in 2019 by Emmanuel Marty + * Portions written in 2014-2015 by Eric Biggers + * + * To the extent possible under law, the author(s) have dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide via the Creative Commons Zero 1.0 Universal Public Domain + * Dedication (the "CC0"). + * + * This software 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 CC0 for more details. + * + * You should have received a copy of the CC0 along with this software; if not + * see . + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#include +#include +#include "matchfinder.h" +#include "format.h" +#include "lib.h" + +/** + * Hash index into TAG_BITS + * + * @param nIndex index value + * + * @return hash + */ +static inline int lzsa_get_index_tag(unsigned int nIndex) { + return (int)(((unsigned long long)nIndex * 11400714819323198485ULL) >> (64ULL - TAG_BITS)); +} + +/** + * Parse input data, build suffix array and overlaid data structures to speed up match finding + * + * @param pCompressor compression context + * @param pInWindow pointer to input data window (previously compressed bytes + bytes to compress) + * @param nInWindowSize total input size in bytes (previously compressed bytes + bytes to compress) + * + * @return 0 for success, non-zero for failure + */ +int lzsa_build_suffix_array(lzsa_compressor *pCompressor, const unsigned char *pInWindow, const int nInWindowSize) { + unsigned int *intervals = pCompressor->intervals; + + /* Build suffix array from input data */ + if (divsufsort_build_array(&pCompressor->divsufsort_context, pInWindow, (saidx_t*)intervals, nInWindowSize) != 0) { + return 100; + } + + int *PLCP = (int*)pCompressor->pos_data; /* Use temporarily */ + int *Phi = PLCP; + int nCurLen = 0; + int i, r; + + /* Compute the permuted LCP first (Kärkkäinen method) */ + Phi[intervals[0]] = -1; + for (i = 1; i < nInWindowSize; i++) + Phi[intervals[i]] = intervals[i - 1]; + for (i = 0; i < nInWindowSize; i++) { + if (Phi[i] == -1) { + PLCP[i] = 0; + continue; + } + int nMaxLen = (i > Phi[i]) ? (nInWindowSize - i) : (nInWindowSize - Phi[i]); + while (nCurLen < nMaxLen && pInWindow[i + nCurLen] == pInWindow[Phi[i] + nCurLen]) nCurLen++; + PLCP[i] = nCurLen; + if (nCurLen > 0) + nCurLen--; + } + + /* Rotate permuted LCP into the LCP. This has better cache locality than the direct Kasai LCP method. This also + * saves us from having to build the inverse suffix array index, as the LCP is calculated without it using this method, + * and the interval builder below doesn't need it either. */ + intervals[0] &= POS_MASK; + int nMinMatchSize = pCompressor->min_match_size; + + if (pCompressor->format_version >= 2) { + for (i = 1; i < nInWindowSize; i++) { + int nIndex = (int)(intervals[i] & POS_MASK); + int nLen = PLCP[nIndex]; + if (nLen < nMinMatchSize) + nLen = 0; + if (nLen > LCP_MAX) + nLen = LCP_MAX; + int nTaggedLen = 0; + if (nLen) + nTaggedLen = (nLen << TAG_BITS) | (lzsa_get_index_tag((unsigned int)nIndex) & ((1 << TAG_BITS) - 1)); + intervals[i] = ((unsigned int)nIndex) | (((unsigned int)nTaggedLen) << LCP_SHIFT); + } + } + else { + for (i = 1; i < nInWindowSize; i++) { + int nIndex = (int)(intervals[i] & POS_MASK); + int nLen = PLCP[nIndex]; + if (nLen < nMinMatchSize) + nLen = 0; + if (nLen > LCP_AND_TAG_MAX) + nLen = LCP_AND_TAG_MAX; + intervals[i] = ((unsigned int)nIndex) | (((unsigned int)nLen) << LCP_SHIFT); + } + } + + /** + * Build intervals for finding matches + * + * Methodology and code fragment taken from wimlib (CC0 license): + * https://wimlib.net/git/?p=wimlib;a=blob_plain;f=src/lcpit_matchfinder.c;h=a2d6a1e0cd95200d1f3a5464d8359d5736b14cbe;hb=HEAD + */ + unsigned int * const SA_and_LCP = intervals; + unsigned int *pos_data = pCompressor->pos_data; + unsigned int next_interval_idx; + unsigned int *top = pCompressor->open_intervals; + unsigned int prev_pos = SA_and_LCP[0] & POS_MASK; + + *top = 0; + intervals[0] = 0; + next_interval_idx = 1; + + for (r = 1; r < nInWindowSize; r++) { + const unsigned int next_pos = SA_and_LCP[r] & POS_MASK; + const unsigned int next_lcp = SA_and_LCP[r] & LCP_MASK; + const unsigned int top_lcp = *top & LCP_MASK; + + if (next_lcp == top_lcp) { + /* Continuing the deepest open interval */ + pos_data[prev_pos] = *top; + } + else if (next_lcp > top_lcp) { + /* Opening a new interval */ + *++top = next_lcp | next_interval_idx++; + pos_data[prev_pos] = *top; + } + else { + /* Closing the deepest open interval */ + pos_data[prev_pos] = *top; + for (;;) { + const unsigned int closed_interval_idx = *top-- & POS_MASK; + const unsigned int superinterval_lcp = *top & LCP_MASK; + + if (next_lcp == superinterval_lcp) { + /* Continuing the superinterval */ + intervals[closed_interval_idx] = *top; + break; + } + else if (next_lcp > superinterval_lcp) { + /* Creating a new interval that is a + * superinterval of the one being + * closed, but still a subinterval of + * its superinterval */ + *++top = next_lcp | next_interval_idx++; + intervals[closed_interval_idx] = *top; + break; + } + else { + /* Also closing the superinterval */ + intervals[closed_interval_idx] = *top; + } + } + } + prev_pos = next_pos; + } + + /* Close any still-open intervals. */ + pos_data[prev_pos] = *top; + for (; top > pCompressor->open_intervals; top--) + intervals[*top & POS_MASK] = *(top - 1); + + /* Success */ + return 0; +} + +/** + * Find matches at the specified offset in the input window + * + * @param pCompressor compression context + * @param nOffset offset to find matches at, in the input window + * @param pMatches pointer to returned matches + * @param nMaxMatches maximum number of matches to return (0 for none) + * @param nInWindowSize total input size in bytes (previously compressed bytes + bytes to compress) + * + * @return number of matches + */ +int lzsa_find_matches_at(lzsa_compressor *pCompressor, const int nOffset, lzsa_match *pMatches, const int nMaxMatches, const int nInWindowSize) { + unsigned int *intervals = pCompressor->intervals; + unsigned int *pos_data = pCompressor->pos_data; + unsigned int ref; + unsigned int super_ref; + unsigned int match_pos; + lzsa_match *matchptr; + int nPrevOffset = 0; + + /** + * Find matches using intervals + * + * Taken from wimlib (CC0 license): + * https://wimlib.net/git/?p=wimlib;a=blob_plain;f=src/lcpit_matchfinder.c;h=a2d6a1e0cd95200d1f3a5464d8359d5736b14cbe;hb=HEAD + */ + + /* Get the deepest lcp-interval containing the current suffix. */ + ref = pos_data[nOffset]; + + pos_data[nOffset] = 0; + + /* Ascend until we reach a visited interval, the root, or a child of the + * root. Link unvisited intervals to the current suffix as we go. */ + while ((super_ref = intervals[ref & POS_MASK]) & LCP_MASK) { + intervals[ref & POS_MASK] = nOffset | VISITED_FLAG; + ref = super_ref; + } + + if (super_ref == 0) { + /* In this case, the current interval may be any of: + * (1) the root; + * (2) an unvisited child of the root */ + + if (ref != 0) /* Not the root? */ + intervals[ref & POS_MASK] = nOffset | VISITED_FLAG; + return 0; + } + + /* Ascend indirectly via pos_data[] links. */ + match_pos = super_ref & EXCL_VISITED_MASK; + matchptr = pMatches; + + if (pCompressor->format_version >= 2 && nInWindowSize < 65536) { + if ((matchptr - pMatches) < nMaxMatches) { + int nMatchOffset = (int)(nOffset - match_pos); + + if (nMatchOffset <= MAX_OFFSET) { + matchptr->length = (unsigned short)(ref >> (LCP_SHIFT + TAG_BITS)); + matchptr->offset = (unsigned short)nMatchOffset; + matchptr++; + + nPrevOffset = nMatchOffset; + } + } + } + + for (;;) { + if ((super_ref = pos_data[match_pos]) > ref) { + match_pos = intervals[super_ref & POS_MASK] & EXCL_VISITED_MASK; + + if (pCompressor->format_version >= 2 && nInWindowSize < 65536) { + if ((matchptr - pMatches) < nMaxMatches) { + int nMatchOffset = (int)(nOffset - match_pos); + + if (nMatchOffset <= MAX_OFFSET && nMatchOffset != nPrevOffset) { + matchptr->length = ((unsigned short)(ref >> (LCP_SHIFT + TAG_BITS))) | 0x8000; + matchptr->offset = (unsigned short)nMatchOffset; + matchptr++; + + nPrevOffset = nMatchOffset; + } + } + } + } + + while ((super_ref = pos_data[match_pos]) > ref) + match_pos = intervals[super_ref & POS_MASK] & EXCL_VISITED_MASK; + intervals[ref & POS_MASK] = nOffset | VISITED_FLAG; + pos_data[match_pos] = ref; + + if ((matchptr - pMatches) < nMaxMatches) { + int nMatchOffset = (int)(nOffset - match_pos); + + if (nMatchOffset <= MAX_OFFSET && nMatchOffset != nPrevOffset) { + if (pCompressor->format_version >= 2) { + matchptr->length = (unsigned short)(ref >> (LCP_SHIFT + TAG_BITS)); + } + else { + matchptr->length = (unsigned short)(ref >> LCP_SHIFT); + } + matchptr->offset = (unsigned short)nMatchOffset; + matchptr++; + } + } + + if (super_ref == 0) + break; + ref = super_ref; + match_pos = intervals[ref & POS_MASK] & EXCL_VISITED_MASK; + + if (pCompressor->format_version >= 2 && nInWindowSize < 65536) { + if ((matchptr - pMatches) < nMaxMatches) { + int nMatchOffset = (int)(nOffset - match_pos); + + if (nMatchOffset <= MAX_OFFSET && nMatchOffset != nPrevOffset) { + matchptr->length = ((unsigned short)(ref >> (LCP_SHIFT + TAG_BITS))) | 0x8000; + matchptr->offset = (unsigned short)nMatchOffset; + + if ((matchptr->length & 0x7fff) > 2) { + matchptr++; + + nPrevOffset = nMatchOffset; + } + } + } + } + } + + return (int)(matchptr - pMatches); +} + +/** + * Skip previously compressed bytes + * + * @param pCompressor compression context + * @param nStartOffset current offset in input window (typically 0) + * @param nEndOffset offset to skip to in input window (typically the number of previously compressed bytes) + */ +void lzsa_skip_matches(lzsa_compressor *pCompressor, const int nStartOffset, const int nEndOffset) { + lzsa_match match; + int i; + + /* Skipping still requires scanning for matches, as this also performs a lazy update of the intervals. However, + * we don't store the matches. */ + for (i = nStartOffset; i < nEndOffset; i++) { + lzsa_find_matches_at(pCompressor, i, &match, 0, 0); + } +} + +/** + * Find all matches for the data to be compressed + * + * @param pCompressor compression context + * @param nMatchesPerOffset maximum number of matches to store for each offset + * @param nStartOffset current offset in input window (typically the number of previously compressed bytes) + * @param nEndOffset offset to end finding matches at (typically the size of the total input window in bytes + */ +void lzsa_find_all_matches(lzsa_compressor *pCompressor, const int nMatchesPerOffset, const int nStartOffset, const int nEndOffset) { + lzsa_match *pMatch = pCompressor->match; + int i; + + for (i = nStartOffset; i < nEndOffset; i++) { + int nMatches = lzsa_find_matches_at(pCompressor, i, pMatch, nMatchesPerOffset, nEndOffset - nStartOffset); + + while (nMatches < nMatchesPerOffset) { + pMatch[nMatches].length = 0; + pMatch[nMatches].offset = 0; + nMatches++; + } + + pMatch += nMatchesPerOffset; + } +} diff --git a/tools/rasm/lzsa-master/src/matchfinder.h b/tools/rasm/lzsa-master/src/matchfinder.h new file mode 100644 index 0000000..cc3b5ab --- /dev/null +++ b/tools/rasm/lzsa-master/src/matchfinder.h @@ -0,0 +1,91 @@ +/* + * matchfinder.h - LZ match finder definitions + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#ifndef _MATCHFINDER_H +#define _MATCHFINDER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declarations */ +typedef struct _lzsa_match lzsa_match; +typedef struct _lzsa_compressor lzsa_compressor; + +/** + * Parse input data, build suffix array and overlaid data structures to speed up match finding + * + * @param pCompressor compression context + * @param pInWindow pointer to input data window (previously compressed bytes + bytes to compress) + * @param nInWindowSize total input size in bytes (previously compressed bytes + bytes to compress) + * + * @return 0 for success, non-zero for failure + */ +int lzsa_build_suffix_array(lzsa_compressor *pCompressor, const unsigned char *pInWindow, const int nInWindowSize); + +/** + * Find matches at the specified offset in the input window + * + * @param pCompressor compression context + * @param nOffset offset to find matches at, in the input window + * @param pMatches pointer to returned matches + * @param nMaxMatches maximum number of matches to return (0 for none) + * @param nInWindowSize total input size in bytes (previously compressed bytes + bytes to compress) + * + * @return number of matches + */ +int lzsa_find_matches_at(lzsa_compressor *pCompressor, const int nOffset, lzsa_match *pMatches, const int nMaxMatches, const int nInWindowSize); + +/** + * Skip previously compressed bytes + * + * @param pCompressor compression context + * @param nStartOffset current offset in input window (typically 0) + * @param nEndOffset offset to skip to in input window (typically the number of previously compressed bytes) + */ +void lzsa_skip_matches(lzsa_compressor *pCompressor, const int nStartOffset, const int nEndOffset); + +/** + * Find all matches for the data to be compressed + * + * @param pCompressor compression context + * @param nMatchesPerOffset maximum number of matches to store for each offset + * @param nStartOffset current offset in input window (typically the number of previously compressed bytes) + * @param nEndOffset offset to end finding matches at (typically the size of the total input window in bytes + */ +void lzsa_find_all_matches(lzsa_compressor *pCompressor, const int nMatchesPerOffset, const int nStartOffset, const int nEndOffset); + +#ifdef __cplusplus +} +#endif + +#endif /* _MATCHFINDER_H */ diff --git a/tools/rasm/lzsa-master/src/shrink_block_v1.c b/tools/rasm/lzsa-master/src/shrink_block_v1.c new file mode 100644 index 0000000..32c5c38 --- /dev/null +++ b/tools/rasm/lzsa-master/src/shrink_block_v1.c @@ -0,0 +1,710 @@ +/* + * shrink_block_v1.c - LZSA1 block compressor implementation + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#include +#include +#include "lib.h" +#include "shrink_block_v1.h" +#include "format.h" + +/** + * Get the number of extra bits required to represent a literals length + * + * @param nLength literals length + * + * @return number of extra bits required + */ +static inline int lzsa_get_literals_varlen_size_v1(const int nLength) { + if (nLength < LITERALS_RUN_LEN_V1) { + return 0; + } + else { + if (nLength < 256) + return 8; + else { + if (nLength < 512) + return 16; + else + return 24; + } + } +} + +/** + * Write extra literals length bytes to output (compressed) buffer. The caller must first check that there is enough + * room to write the bytes. + * + * @param pOutData pointer to output buffer + * @param nOutOffset current write index into output buffer + * @param nLength literals length + */ +static inline int lzsa_write_literals_varlen_v1(unsigned char *pOutData, int nOutOffset, int nLength) { + if (nLength >= LITERALS_RUN_LEN_V1) { + if (nLength < 256) + pOutData[nOutOffset++] = nLength - LITERALS_RUN_LEN_V1; + else { + if (nLength < 512) { + pOutData[nOutOffset++] = 250; + pOutData[nOutOffset++] = nLength - 256; + } + else { + pOutData[nOutOffset++] = 249; + pOutData[nOutOffset++] = nLength & 0xff; + pOutData[nOutOffset++] = (nLength >> 8) & 0xff; + } + } + } + + return nOutOffset; +} + +/** + * Get the number of extra bits required to represent an encoded match length + * + * @param nLength encoded match length (actual match length - MIN_MATCH_SIZE_V1) + * + * @return number of extra bits required + */ +static inline int lzsa_get_match_varlen_size_v1(const int nLength) { + if (nLength < MATCH_RUN_LEN_V1) { + return 0; + } + else { + if ((nLength + MIN_MATCH_SIZE_V1) < 256) + return 8; + else { + if ((nLength + MIN_MATCH_SIZE_V1) < 512) + return 16; + else + return 24; + } + } +} + +/** + * Write extra encoded match length bytes to output (compressed) buffer. The caller must first check that there is enough + * room to write the bytes. + * + * @param pOutData pointer to output buffer + * @param nOutOffset current write index into output buffer + * @param nLength encoded match length (actual match length - MIN_MATCH_SIZE_V1) + */ +static inline int lzsa_write_match_varlen_v1(unsigned char *pOutData, int nOutOffset, int nLength) { + if (nLength >= MATCH_RUN_LEN_V1) { + if ((nLength + MIN_MATCH_SIZE_V1) < 256) + pOutData[nOutOffset++] = nLength - MATCH_RUN_LEN_V1; + else { + if ((nLength + MIN_MATCH_SIZE_V1) < 512) { + pOutData[nOutOffset++] = 239; + pOutData[nOutOffset++] = nLength + MIN_MATCH_SIZE_V1 - 256; + } + else { + pOutData[nOutOffset++] = 238; + pOutData[nOutOffset++] = (nLength + MIN_MATCH_SIZE_V1) & 0xff; + pOutData[nOutOffset++] = ((nLength + MIN_MATCH_SIZE_V1) >> 8) & 0xff; + } + } + } + + return nOutOffset; +} + +/** + * Get offset encoding cost in bits + * + * @param nMatchOffset offset to get cost of + * + * @return cost in bits + */ +static inline int lzsa_get_offset_cost_v1(const unsigned int nMatchOffset) { + return (nMatchOffset <= 256) ? 8 : 16; +} + +/** + * Attempt to pick optimal matches using a forward arrivals parser, so as to produce the smallest possible output that decompresses to the same input + * + * @param pCompressor compression context + * @param nStartOffset current offset in input window (typically the number of previously compressed bytes) + * @param nEndOffset offset to end finding matches at (typically the size of the total input window in bytes + */ +static void lzsa_optimize_forward_v1(lzsa_compressor *pCompressor, lzsa_match *pBestMatch, const int nStartOffset, const int nEndOffset, const int nReduce) { + lzsa_arrival *arrival = pCompressor->arrival - (nStartOffset << ARRIVALS_PER_POSITION_SHIFT); + const int nMinMatchSize = pCompressor->min_match_size; + const int nFavorRatio = (pCompressor->flags & LZSA_FLAG_FAVOR_RATIO) ? 1 : 0; + const int nModeSwitchPenalty = nFavorRatio ? 0 : MODESWITCH_PENALTY; + const int nDisableScore = nReduce ? 0 : (2 * BLOCK_SIZE); + int i, j, n; + + if ((nEndOffset - nStartOffset) > BLOCK_SIZE) return; + + memset(arrival + (nStartOffset << ARRIVALS_PER_POSITION_SHIFT), 0, sizeof(lzsa_arrival) * ((nEndOffset - nStartOffset + 1) << ARRIVALS_PER_POSITION_SHIFT)); + + arrival[nStartOffset << ARRIVALS_PER_POSITION_SHIFT].from_slot = -1; + + for (i = nStartOffset; i != nEndOffset; i++) { + lzsa_arrival* cur_arrival = &arrival[i << ARRIVALS_PER_POSITION_SHIFT]; + int m; + + for (j = 0; j < NARRIVALS_PER_POSITION_V1 && cur_arrival[j].from_slot; j++) { + int nPrevCost = cur_arrival[j].cost; + int nCodingChoiceCost = nPrevCost + 8 /* literal */; + int nScore = cur_arrival[j].score + 1; + int nNumLiterals = cur_arrival[j].num_literals + 1; + + if (nNumLiterals == LITERALS_RUN_LEN_V1 || nNumLiterals == 256 || nNumLiterals == 512) { + nCodingChoiceCost += 8; + } + + if (nNumLiterals == 1) + nCodingChoiceCost += nModeSwitchPenalty; + + lzsa_arrival *pDestSlots = &arrival[(i + 1) << ARRIVALS_PER_POSITION_SHIFT]; + for (n = 0; n < NARRIVALS_PER_POSITION_V1 /* we only need the literals + short match cost + long match cost cases */; n++) { + lzsa_arrival *pDestArrival = &pDestSlots[n]; + + if (pDestArrival->from_slot == 0 || + nCodingChoiceCost < pDestArrival->cost || + (nCodingChoiceCost == pDestArrival->cost && nScore < (pDestArrival->score + nDisableScore))) { + memmove(&arrival[((i + 1) << ARRIVALS_PER_POSITION_SHIFT) + n + 1], + &arrival[((i + 1) << ARRIVALS_PER_POSITION_SHIFT) + n], + sizeof(lzsa_arrival) * (NARRIVALS_PER_POSITION_V1 - n - 1)); + + pDestArrival->cost = nCodingChoiceCost; + pDestArrival->from_pos = i; + pDestArrival->from_slot = j + 1; + pDestArrival->match_len = 0; + pDestArrival->num_literals = nNumLiterals; + pDestArrival->score = nScore; + pDestArrival->rep_offset = cur_arrival[j].rep_offset; + break; + } + } + } + + const lzsa_match *match = pCompressor->match + ((i - nStartOffset) << MATCHES_PER_INDEX_SHIFT_V1); + int nNumArrivalsForThisPos = j; + + for (m = 0; m < NMATCHES_PER_INDEX_V1 && match[m].length; m++) { + int nMatchLen = match[m].length; + int nMatchOffsetCost = lzsa_get_offset_cost_v1(match[m].offset); + int nStartingMatchLen, k; + + if ((i + nMatchLen) > nEndOffset) + nMatchLen = nEndOffset - i; + + if (nMatchLen >= LEAVE_ALONE_MATCH_SIZE) + nStartingMatchLen = nMatchLen; + else + nStartingMatchLen = nMinMatchSize; + for (k = nStartingMatchLen; k <= nMatchLen; k++) { + int nMatchLenCost = lzsa_get_match_varlen_size_v1(k - MIN_MATCH_SIZE_V1); + + lzsa_arrival *pDestSlots = &arrival[(i + k) << ARRIVALS_PER_POSITION_SHIFT]; + + for (j = 0; j < nNumArrivalsForThisPos; j++) { + int nPrevCost = cur_arrival[j].cost; + int nCodingChoiceCost = nPrevCost + 8 /* token */ /* the actual cost of the literals themselves accumulates up the chain */ + nMatchOffsetCost + nMatchLenCost; + int exists = 0; + + if (!cur_arrival[j].num_literals) + nCodingChoiceCost += nModeSwitchPenalty; + + for (n = 0; + n < NARRIVALS_PER_POSITION_V1 && pDestSlots[n].from_slot && pDestSlots[n].cost <= nCodingChoiceCost; + n++) { + if (lzsa_get_offset_cost_v1(pDestSlots[n].rep_offset) == nMatchOffsetCost) { + exists = 1; + break; + } + } + + if (!exists) { + int nScore = cur_arrival[j].score + 5; + + for (n = 0; n < NARRIVALS_PER_POSITION_V1 /* we only need the literals + short match cost + long match cost cases */; n++) { + lzsa_arrival *pDestArrival = &pDestSlots[n]; + + if (pDestArrival->from_slot == 0 || + nCodingChoiceCost < pDestArrival->cost || + (nCodingChoiceCost == pDestArrival->cost && nScore < (pDestArrival->score + nDisableScore))) { + memmove(&pDestSlots[n + 1], + &pDestSlots[n], + sizeof(lzsa_arrival) * (NARRIVALS_PER_POSITION_V1 - n - 1)); + + pDestArrival->cost = nCodingChoiceCost; + pDestArrival->from_pos = i; + pDestArrival->from_slot = j + 1; + pDestArrival->match_len = k; + pDestArrival->num_literals = 0; + pDestArrival->score = nScore; + pDestArrival->rep_offset = match[m].offset; + j = NARRIVALS_PER_POSITION_V1; + break; + } + } + } + } + } + } + } + + lzsa_arrival *end_arrival = &arrival[(i << ARRIVALS_PER_POSITION_SHIFT) + 0]; + + while (end_arrival->from_slot > 0 && end_arrival->from_pos >= 0) { + if (end_arrival->from_pos >= nEndOffset) return; + pBestMatch[end_arrival->from_pos].length = end_arrival->match_len; + if (end_arrival->match_len) + pBestMatch[end_arrival->from_pos].offset = end_arrival->rep_offset; + else + pBestMatch[end_arrival->from_pos].offset = 0; + + end_arrival = &arrival[(end_arrival->from_pos << ARRIVALS_PER_POSITION_SHIFT) + (end_arrival->from_slot - 1)]; + } +} + +/** + * Attempt to minimize the number of commands issued in the compressed data block, in order to speed up decompression without + * impacting the compression ratio + * + * @param pCompressor compression context + * @param pInWindow pointer to input data window (previously compressed bytes + bytes to compress) + * @param pBestMatch optimal matches to emit + * @param nStartOffset current offset in input window (typically the number of previously compressed bytes) + * @param nEndOffset offset to end finding matches at (typically the size of the total input window in bytes + * + * @return non-zero if the number of tokens was reduced, 0 if it wasn't + */ +static int lzsa_optimize_command_count_v1(lzsa_compressor *pCompressor, const unsigned char *pInWindow, lzsa_match *pBestMatch, const int nStartOffset, const int nEndOffset) { + int i; + int nNumLiterals = 0; + int nDidReduce = 0; + + for (i = nStartOffset; i < nEndOffset; ) { + lzsa_match *pMatch = pBestMatch + i; + + if (pMatch->length == 0 && + (i + 1) < nEndOffset && + pBestMatch[i + 1].length >= MIN_MATCH_SIZE_V1 && + pBestMatch[i + 1].length < MAX_VARLEN && + pBestMatch[i + 1].offset && + i >= pBestMatch[i + 1].offset && + (i + pBestMatch[i + 1].length + 1) <= nEndOffset && + !memcmp(pInWindow + i - (pBestMatch[i + 1].offset), pInWindow + i, pBestMatch[i + 1].length + 1)) { + int nCurLenSize = lzsa_get_match_varlen_size_v1(pBestMatch[i + 1].length - MIN_MATCH_SIZE_V1); + int nReducedLenSize = lzsa_get_match_varlen_size_v1(pBestMatch[i + 1].length + 1 - MIN_MATCH_SIZE_V1); + + if ((nReducedLenSize - nCurLenSize) <= 8) { + /* Merge */ + pBestMatch[i].length = pBestMatch[i + 1].length + 1; + pBestMatch[i].offset = pBestMatch[i + 1].offset; + pBestMatch[i + 1].length = 0; + pBestMatch[i + 1].offset = 0; + nDidReduce = 1; + continue; + } + } + + if (pMatch->length >= MIN_MATCH_SIZE_V1) { + if (pMatch->length <= 9 /* Don't waste time considering large matches, they will always win over literals */ && + (i + pMatch->length) < nEndOffset /* Don't consider the last token in the block, we can only reduce a match inbetween other tokens */) { + int nNextIndex = i + pMatch->length; + int nNextLiterals = 0; + + while (nNextIndex < nEndOffset && pBestMatch[nNextIndex].length < MIN_MATCH_SIZE_V1) { + nNextLiterals++; + nNextIndex++; + } + + /* This command is a match, is followed by 'nNextLiterals' literals and then by another match, or the end of the input. Calculate this command's current cost (excluding 'nNumLiterals' bytes) */ + if ((8 /* token */ + lzsa_get_literals_varlen_size_v1(nNumLiterals) + ((pMatch->offset <= 256) ? 8 : 16) /* match offset */ + lzsa_get_match_varlen_size_v1(pMatch->length - MIN_MATCH_SIZE_V1) + + 8 /* token */ + lzsa_get_literals_varlen_size_v1(nNextLiterals)) >= + (8 /* token */ + (pMatch->length << 3) + lzsa_get_literals_varlen_size_v1(nNumLiterals + pMatch->length + nNextLiterals))) { + /* Reduce */ + int nMatchLen = pMatch->length; + int j; + + for (j = 0; j < nMatchLen; j++) { + pBestMatch[i + j].length = 0; + } + + nDidReduce = 1; + continue; + } + } + + if ((i + pMatch->length) <= nEndOffset && pMatch->offset > 0 && pMatch->length >= MIN_MATCH_SIZE_V1 && + pBestMatch[i + pMatch->length].offset > 0 && + pBestMatch[i + pMatch->length].length >= MIN_MATCH_SIZE_V1 && + (pMatch->length + pBestMatch[i + pMatch->length].length) >= LEAVE_ALONE_MATCH_SIZE && + (pMatch->length + pBestMatch[i + pMatch->length].length) <= MAX_VARLEN && + (i + pMatch->length) > pMatch->offset && + (i + pMatch->length) > pBestMatch[i + pMatch->length].offset && + (i + pMatch->length + pBestMatch[i + pMatch->length].length) <= nEndOffset && + !memcmp(pInWindow + i - pMatch->offset + pMatch->length, + pInWindow + i + pMatch->length - pBestMatch[i + pMatch->length].offset, + pBestMatch[i + pMatch->length].length)) { + + int nCurPartialSize = lzsa_get_match_varlen_size_v1(pMatch->length - MIN_MATCH_SIZE_V1); + nCurPartialSize += 8 /* token */ + lzsa_get_literals_varlen_size_v1(0) + ((pBestMatch[i + pMatch->length].offset <= 256) ? 8 : 16) /* match offset */ + lzsa_get_match_varlen_size_v1(pBestMatch[i + pMatch->length].length - MIN_MATCH_SIZE_V1); + + int nReducedPartialSize = lzsa_get_match_varlen_size_v1(pMatch->length + pBestMatch[i + pMatch->length].length - MIN_MATCH_SIZE_V1); + + if (nCurPartialSize >= nReducedPartialSize) { + int nMatchLen = pMatch->length; + + /* Join */ + + pMatch->length += pBestMatch[i + nMatchLen].length; + pBestMatch[i + nMatchLen].offset = 0; + pBestMatch[i + nMatchLen].length = -1; + continue; + } + } + + i += pMatch->length; + nNumLiterals = 0; + } + else { + nNumLiterals++; + i++; + } + } + + return nDidReduce; +} + +/** + * Get compressed data block size + * + * @param pCompressor compression context + * @param pBestMatch optimal matches to emit + * @param nStartOffset current offset in input window (typically the number of previously compressed bytes) + * @param nEndOffset offset to end finding matches at (typically the size of the total input window in bytes + * + * @return size of compressed data that will be written to output buffer + */ +static int lzsa_get_compressed_size_v1(lzsa_compressor *pCompressor, lzsa_match *pBestMatch, const int nStartOffset, const int nEndOffset) { + int i; + int nNumLiterals = 0; + int nCompressedSize = 0; + + for (i = nStartOffset; i < nEndOffset; ) { + const lzsa_match *pMatch = pBestMatch + i; + + if (pMatch->length >= MIN_MATCH_SIZE_V1) { + int nMatchOffset = pMatch->offset; + int nMatchLen = pMatch->length; + int nEncodedMatchLen = nMatchLen - MIN_MATCH_SIZE_V1; + int nTokenLongOffset = (nMatchOffset <= 256) ? 0x00 : 0x80; + int nCommandSize = 8 /* token */ + lzsa_get_literals_varlen_size_v1(nNumLiterals) + (nNumLiterals << 3) + (nTokenLongOffset ? 16 : 8) /* match offset */ + lzsa_get_match_varlen_size_v1(nEncodedMatchLen); + + nCompressedSize += nCommandSize; + nNumLiterals = 0; + i += nMatchLen; + } + else { + nNumLiterals++; + i++; + } + } + + { + int nCommandSize = 8 /* token */ + lzsa_get_literals_varlen_size_v1(nNumLiterals) + (nNumLiterals << 3); + + nCompressedSize += nCommandSize; + nNumLiterals = 0; + } + + if (pCompressor->flags & LZSA_FLAG_RAW_BLOCK) { + nCompressedSize += 8 * 4; + } + + return nCompressedSize; +} + +/** + * Emit block of compressed data + * + * @param pCompressor compression context + * @param pBestMatch optimal matches to emit + * @param pInWindow pointer to input data window (previously compressed bytes + bytes to compress) + * @param nStartOffset current offset in input window (typically the number of previously compressed bytes) + * @param nEndOffset offset to end finding matches at (typically the size of the total input window in bytes + * @param pOutData pointer to output buffer + * @param nMaxOutDataSize maximum size of output buffer, in bytes + * + * @return size of compressed data in output buffer, or -1 if the data is uncompressible + */ +static int lzsa_write_block_v1(lzsa_compressor *pCompressor, lzsa_match *pBestMatch, const unsigned char *pInWindow, const int nStartOffset, const int nEndOffset, unsigned char *pOutData, const int nMaxOutDataSize) { + int i; + int nNumLiterals = 0; + int nInFirstLiteralOffset = 0; + int nOutOffset = 0; + + for (i = nStartOffset; i < nEndOffset; ) { + const lzsa_match *pMatch = pBestMatch + i; + + if (pMatch->length >= MIN_MATCH_SIZE_V1) { + int nMatchOffset = pMatch->offset; + int nMatchLen = pMatch->length; + int nEncodedMatchLen = nMatchLen - MIN_MATCH_SIZE_V1; + int nTokenLiteralsLen = (nNumLiterals >= LITERALS_RUN_LEN_V1) ? LITERALS_RUN_LEN_V1 : nNumLiterals; + int nTokenMatchLen = (nEncodedMatchLen >= MATCH_RUN_LEN_V1) ? MATCH_RUN_LEN_V1 : nEncodedMatchLen; + int nTokenLongOffset = (nMatchOffset <= 256) ? 0x00 : 0x80; + int nCommandSize = 8 /* token */ + lzsa_get_literals_varlen_size_v1(nNumLiterals) + (nNumLiterals << 3) + (nTokenLongOffset ? 16 : 8) /* match offset */ + lzsa_get_match_varlen_size_v1(nEncodedMatchLen); + + if ((nOutOffset + (nCommandSize >> 3)) > nMaxOutDataSize) + return -1; + if (nMatchOffset < MIN_OFFSET || nMatchOffset > MAX_OFFSET) + return -1; + + pOutData[nOutOffset++] = nTokenLongOffset | (nTokenLiteralsLen << 4) | nTokenMatchLen; + nOutOffset = lzsa_write_literals_varlen_v1(pOutData, nOutOffset, nNumLiterals); + + if (nNumLiterals < pCompressor->stats.min_literals || pCompressor->stats.min_literals == -1) + pCompressor->stats.min_literals = nNumLiterals; + if (nNumLiterals > pCompressor->stats.max_literals) + pCompressor->stats.max_literals = nNumLiterals; + pCompressor->stats.total_literals += nNumLiterals; + pCompressor->stats.literals_divisor++; + + if (nNumLiterals != 0) { + memcpy(pOutData + nOutOffset, pInWindow + nInFirstLiteralOffset, nNumLiterals); + nOutOffset += nNumLiterals; + nNumLiterals = 0; + } + + pOutData[nOutOffset++] = (-nMatchOffset) & 0xff; + if (nTokenLongOffset) { + pOutData[nOutOffset++] = (-nMatchOffset) >> 8; + } + nOutOffset = lzsa_write_match_varlen_v1(pOutData, nOutOffset, nEncodedMatchLen); + + if (nMatchOffset < pCompressor->stats.min_offset || pCompressor->stats.min_offset == -1) + pCompressor->stats.min_offset = nMatchOffset; + if (nMatchOffset > pCompressor->stats.max_offset) + pCompressor->stats.max_offset = nMatchOffset; + pCompressor->stats.total_offsets += nMatchOffset; + + if (nMatchLen < pCompressor->stats.min_match_len || pCompressor->stats.min_match_len == -1) + pCompressor->stats.min_match_len = nMatchLen; + if (nMatchLen > pCompressor->stats.max_match_len) + pCompressor->stats.max_match_len = nMatchLen; + pCompressor->stats.total_match_lens += nMatchLen; + pCompressor->stats.match_divisor++; + + if (nMatchOffset == 1) { + if (nMatchLen < pCompressor->stats.min_rle1_len || pCompressor->stats.min_rle1_len == -1) + pCompressor->stats.min_rle1_len = nMatchLen; + if (nMatchLen > pCompressor->stats.max_rle1_len) + pCompressor->stats.max_rle1_len = nMatchLen; + pCompressor->stats.total_rle1_lens += nMatchLen; + pCompressor->stats.rle1_divisor++; + } + else if (nMatchOffset == 2) { + if (nMatchLen < pCompressor->stats.min_rle2_len || pCompressor->stats.min_rle2_len == -1) + pCompressor->stats.min_rle2_len = nMatchLen; + if (nMatchLen > pCompressor->stats.max_rle2_len) + pCompressor->stats.max_rle2_len = nMatchLen; + pCompressor->stats.total_rle2_lens += nMatchLen; + pCompressor->stats.rle2_divisor++; + } + + i += nMatchLen; + + if (pCompressor->flags & LZSA_FLAG_RAW_BLOCK) { + int nCurSafeDist = (i - nStartOffset) - nOutOffset; + if (nCurSafeDist >= 0 && pCompressor->safe_dist < nCurSafeDist) + pCompressor->safe_dist = nCurSafeDist; + } + + pCompressor->num_commands++; + } + else { + if (nNumLiterals == 0) + nInFirstLiteralOffset = i; + nNumLiterals++; + i++; + } + } + + { + int nTokenLiteralsLen = (nNumLiterals >= LITERALS_RUN_LEN_V1) ? LITERALS_RUN_LEN_V1 : nNumLiterals; + int nCommandSize = 8 /* token */ + lzsa_get_literals_varlen_size_v1(nNumLiterals) + (nNumLiterals << 3); + + if ((nOutOffset + (nCommandSize >> 3)) > nMaxOutDataSize) + return -1; + + if (pCompressor->flags & LZSA_FLAG_RAW_BLOCK) + pOutData[nOutOffset++] = (nTokenLiteralsLen << 4) | 0x0f; + else + pOutData[nOutOffset++] = (nTokenLiteralsLen << 4) | 0x00; + nOutOffset = lzsa_write_literals_varlen_v1(pOutData, nOutOffset, nNumLiterals); + + if (nNumLiterals < pCompressor->stats.min_literals || pCompressor->stats.min_literals == -1) + pCompressor->stats.min_literals = nNumLiterals; + if (nNumLiterals > pCompressor->stats.max_literals) + pCompressor->stats.max_literals = nNumLiterals; + pCompressor->stats.total_literals += nNumLiterals; + pCompressor->stats.literals_divisor++; + + if (nNumLiterals != 0) { + memcpy(pOutData + nOutOffset, pInWindow + nInFirstLiteralOffset, nNumLiterals); + nOutOffset += nNumLiterals; + nNumLiterals = 0; + } + + if (pCompressor->flags & LZSA_FLAG_RAW_BLOCK) { + int nCurSafeDist = (i - nStartOffset) - nOutOffset; + if (nCurSafeDist >= 0 && pCompressor->safe_dist < nCurSafeDist) + pCompressor->safe_dist = nCurSafeDist; + } + + pCompressor->num_commands++; + } + + if (pCompressor->flags & LZSA_FLAG_RAW_BLOCK) { + /* Emit EOD marker for raw block */ + + if ((nOutOffset + 4) > nMaxOutDataSize) + return -1; + + pOutData[nOutOffset++] = 0; + pOutData[nOutOffset++] = 238; + pOutData[nOutOffset++] = 0; + pOutData[nOutOffset++] = 0; + } + + return nOutOffset; +} + +/** + * Emit raw block of uncompressible data + * + * @param pCompressor compression context + * @param pInWindow pointer to input data window (previously compressed bytes + bytes to compress) + * @param nStartOffset current offset in input window (typically the number of previously compressed bytes) + * @param nEndOffset offset to end finding matches at (typically the size of the total input window in bytes + * @param pOutData pointer to output buffer + * @param nMaxOutDataSize maximum size of output buffer, in bytes + * + * @return size of compressed data in output buffer, or -1 if the data is uncompressible + */ +static int lzsa_write_raw_uncompressed_block_v1(lzsa_compressor *pCompressor, const unsigned char *pInWindow, const int nStartOffset, const int nEndOffset, unsigned char *pOutData, const int nMaxOutDataSize) { + int nNumLiterals = nEndOffset - nStartOffset; + int nTokenLiteralsLen = (nNumLiterals >= LITERALS_RUN_LEN_V1) ? LITERALS_RUN_LEN_V1 : nNumLiterals; + int nOutOffset = 0; + + int nCommandSize = 8 /* token */ + lzsa_get_literals_varlen_size_v1(nNumLiterals) + (nNumLiterals << 3) + 4; + if ((nOutOffset + (nCommandSize >> 3)) > nMaxOutDataSize) + return -1; + + pCompressor->num_commands = 0; + pOutData[nOutOffset++] = (nTokenLiteralsLen << 4) | 0x0f; + + nOutOffset = lzsa_write_literals_varlen_v1(pOutData, nOutOffset, nNumLiterals); + + if (nNumLiterals != 0) { + memcpy(pOutData + nOutOffset, pInWindow + nStartOffset, nNumLiterals); + nOutOffset += nNumLiterals; + nNumLiterals = 0; + } + + pCompressor->num_commands++; + + /* Emit EOD marker for raw block */ + + pOutData[nOutOffset++] = 0; + pOutData[nOutOffset++] = 238; + pOutData[nOutOffset++] = 0; + pOutData[nOutOffset++] = 0; + + return nOutOffset; +} + +/** + * Select the most optimal matches, reduce the token count if possible, and then emit a block of compressed LZSA1 data + * + * @param pCompressor compression context + * @param pInWindow pointer to input data window (previously compressed bytes + bytes to compress) + * @param nPreviousBlockSize number of previously compressed bytes (or 0 for none) + * @param nInDataSize number of input bytes to compress + * @param pOutData pointer to output buffer + * @param nMaxOutDataSize maximum size of output buffer, in bytes + * + * @return size of compressed data in output buffer, or -1 if the data is uncompressible + */ +int lzsa_optimize_and_write_block_v1(lzsa_compressor *pCompressor, const unsigned char *pInWindow, const int nPreviousBlockSize, const int nInDataSize, unsigned char *pOutData, const int nMaxOutDataSize) { + int nResult, nBaseCompressedSize; + + /* Compress optimally without breaking ties in favor of less tokens */ + + memset(pCompressor->best_match, 0, BLOCK_SIZE * sizeof(lzsa_match)); + lzsa_optimize_forward_v1(pCompressor, pCompressor->best_match - nPreviousBlockSize, nPreviousBlockSize, nPreviousBlockSize + nInDataSize, 0 /* reduce */); + + int nDidReduce; + int nPasses = 0; + do { + nDidReduce = lzsa_optimize_command_count_v1(pCompressor, pInWindow, pCompressor->best_match - nPreviousBlockSize, nPreviousBlockSize, nPreviousBlockSize + nInDataSize); + nPasses++; + } while (nDidReduce && nPasses < 20); + + nBaseCompressedSize = lzsa_get_compressed_size_v1(pCompressor, pCompressor->best_match - nPreviousBlockSize, nPreviousBlockSize, nPreviousBlockSize + nInDataSize); + lzsa_match *pBestMatch = pCompressor->best_match - nPreviousBlockSize; + + if (nBaseCompressedSize > 0 && nInDataSize < 65536) { + int nReducedCompressedSize; + + /* Compress optimally and do break ties in favor of less tokens */ + memset(pCompressor->improved_match, 0, BLOCK_SIZE * sizeof(lzsa_match)); + lzsa_optimize_forward_v1(pCompressor, pCompressor->improved_match - nPreviousBlockSize, nPreviousBlockSize, nPreviousBlockSize + nInDataSize, 1 /* reduce */); + + nPasses = 0; + do { + nDidReduce = lzsa_optimize_command_count_v1(pCompressor, pInWindow, pCompressor->improved_match - nPreviousBlockSize, nPreviousBlockSize, nPreviousBlockSize + nInDataSize); + nPasses++; + } while (nDidReduce && nPasses < 20); + + nReducedCompressedSize = lzsa_get_compressed_size_v1(pCompressor, pCompressor->improved_match - nPreviousBlockSize, nPreviousBlockSize, nPreviousBlockSize + nInDataSize); + if (nReducedCompressedSize > 0 && nReducedCompressedSize <= nBaseCompressedSize) { + /* Pick the parse with the reduced number of tokens as it didn't negatively affect the size */ + pBestMatch = pCompressor->improved_match - nPreviousBlockSize; + } + } + + nResult = lzsa_write_block_v1(pCompressor, pBestMatch, pInWindow, nPreviousBlockSize, nPreviousBlockSize + nInDataSize, pOutData, nMaxOutDataSize); + if (nResult < 0 && pCompressor->flags & LZSA_FLAG_RAW_BLOCK) { + nResult = lzsa_write_raw_uncompressed_block_v1(pCompressor, pInWindow, nPreviousBlockSize, nPreviousBlockSize + nInDataSize, pOutData, nMaxOutDataSize); + } + + return nResult; +} diff --git a/tools/rasm/lzsa-master/src/shrink_block_v1.h b/tools/rasm/lzsa-master/src/shrink_block_v1.h new file mode 100644 index 0000000..cc89cde --- /dev/null +++ b/tools/rasm/lzsa-master/src/shrink_block_v1.h @@ -0,0 +1,53 @@ +/* + * shrink_block_v1.h - LZSA1 block compressor definitions + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#ifndef _SHRINK_BLOCK_V1_H +#define _SHRINK_BLOCK_V1_H + +/* Forward declarations */ +typedef struct _lzsa_compressor lzsa_compressor; + +/** + * Select the most optimal matches, reduce the token count if possible, and then emit a block of compressed LZSA1 data + * + * @param pCompressor compression context + * @param pInWindow pointer to input data window (previously compressed bytes + bytes to compress) + * @param nPreviousBlockSize number of previously compressed bytes (or 0 for none) + * @param nInDataSize number of input bytes to compress + * @param pOutData pointer to output buffer + * @param nMaxOutDataSize maximum size of output buffer, in bytes + * + * @return size of compressed data in output buffer, or -1 if the data is uncompressible + */ +int lzsa_optimize_and_write_block_v1(lzsa_compressor *pCompressor, const unsigned char *pInWindow, const int nPreviousBlockSize, const int nInDataSize, unsigned char *pOutData, const int nMaxOutDataSize); + +#endif /* _SHRINK_BLOCK_V1_H */ diff --git a/tools/rasm/lzsa-master/src/shrink_block_v2.c b/tools/rasm/lzsa-master/src/shrink_block_v2.c new file mode 100644 index 0000000..0aba0c0 --- /dev/null +++ b/tools/rasm/lzsa-master/src/shrink_block_v2.c @@ -0,0 +1,1371 @@ +/* + * shrink_block_v2.c - LZSA2 block compressor implementation + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#include +#include +#include "lib.h" +#include "shrink_block_v2.h" +#include "format.h" + +/** + * Write 4-bit nibble to output (compressed) buffer + * + * @param pOutData pointer to output buffer + * @param nOutOffset current write index into output buffer + * @param nMaxOutDataSize maximum size of output buffer, in bytes + * @param nCurNibbleOffset write index into output buffer, of current byte being filled with nibbles + * @param nNibbleValue value to write (0..15) + */ +static int lzsa_write_nibble_v2(unsigned char *pOutData, int nOutOffset, const int nMaxOutDataSize, int *nCurNibbleOffset, int nNibbleValue) { + if (nOutOffset < 0) return -1; + + if ((*nCurNibbleOffset) == -1) { + if (nOutOffset >= nMaxOutDataSize) return -1; + (*nCurNibbleOffset) = nOutOffset; + pOutData[nOutOffset++] = nNibbleValue << 4; + } + else { + pOutData[*nCurNibbleOffset] = (pOutData[*nCurNibbleOffset]) | (nNibbleValue & 0x0f); + (*nCurNibbleOffset) = -1; + } + + return nOutOffset; +} + +/** + * Get the number of extra bits required to represent a literals length + * + * @param nLength literals length + * + * @return number of extra bits required + */ +static inline int lzsa_get_literals_varlen_size_v2(const int nLength) { + if (nLength < LITERALS_RUN_LEN_V2) { + return 0; + } + else { + if (nLength < (LITERALS_RUN_LEN_V2 + 15)) { + return 4; + } + else { + if (nLength < 256) + return 4+8; + else { + return 4+24; + } + } + } +} + +/** + * Write extra literals length bytes to output (compressed) buffer. The caller must first check that there is enough + * room to write the bytes. + * + * @param pOutData pointer to output buffer + * @param nOutOffset current write index into output buffer + * @param nMaxOutDataSize maximum size of output buffer, in bytes + * @param nCurNibbleOffset write index into output buffer, of current byte being filled with nibbles + * @param nLength literals length + */ +static inline int lzsa_write_literals_varlen_v2(unsigned char *pOutData, int nOutOffset, const int nMaxOutDataSize, int *nCurNibbleOffset, int nLength) { + if (nLength >= LITERALS_RUN_LEN_V2) { + if (nLength < (LITERALS_RUN_LEN_V2 + 15)) { + nOutOffset = lzsa_write_nibble_v2(pOutData, nOutOffset, nMaxOutDataSize, nCurNibbleOffset, nLength - LITERALS_RUN_LEN_V2); + } + else { + nOutOffset = lzsa_write_nibble_v2(pOutData, nOutOffset, nMaxOutDataSize, nCurNibbleOffset, 15); + if (nOutOffset < 0) return -1; + + if (nLength < 256) + pOutData[nOutOffset++] = nLength - 18; + else { + pOutData[nOutOffset++] = 239; + pOutData[nOutOffset++] = nLength & 0xff; + pOutData[nOutOffset++] = (nLength >> 8) & 0xff; + } + } + } + + return nOutOffset; +} + +/** + * Get the number of extra bits required to represent an encoded match length + * + * @param nLength encoded match length (actual match length - MIN_MATCH_SIZE_V2) + * + * @return number of extra bits required + */ +static inline int lzsa_get_match_varlen_size_v2(const int nLength) { + if (nLength < MATCH_RUN_LEN_V2) { + return 0; + } + else { + if (nLength < (MATCH_RUN_LEN_V2 + 15)) + return 4; + else { + if ((nLength + MIN_MATCH_SIZE_V2) < 256) + return 4+8; + else { + return 4 + 24; + } + } + } +} + +/** + * Write extra encoded match length bytes to output (compressed) buffer. The caller must first check that there is enough + * room to write the bytes. + * + * @param pOutData pointer to output buffer + * @param nOutOffset current write index into output buffer + * @param nMaxOutDataSize maximum size of output buffer, in bytes + * @param nCurNibbleOffset write index into output buffer, of current byte being filled with nibbles + * @param nLength encoded match length (actual match length - MIN_MATCH_SIZE_V2) + */ +static inline int lzsa_write_match_varlen_v2(unsigned char *pOutData, int nOutOffset, const int nMaxOutDataSize, int *nCurNibbleOffset, int nLength) { + if (nLength >= MATCH_RUN_LEN_V2) { + if (nLength < (MATCH_RUN_LEN_V2 + 15)) { + nOutOffset = lzsa_write_nibble_v2(pOutData, nOutOffset, nMaxOutDataSize, nCurNibbleOffset, nLength - MATCH_RUN_LEN_V2); + } + else { + nOutOffset = lzsa_write_nibble_v2(pOutData, nOutOffset, nMaxOutDataSize, nCurNibbleOffset, 15); + if (nOutOffset < 0) return -1; + + if ((nLength + MIN_MATCH_SIZE_V2) < 256) + pOutData[nOutOffset++] = nLength + MIN_MATCH_SIZE_V2 - 24; + else { + pOutData[nOutOffset++] = 233; + pOutData[nOutOffset++] = (nLength + MIN_MATCH_SIZE_V2) & 0xff; + pOutData[nOutOffset++] = ((nLength + MIN_MATCH_SIZE_V2) >> 8) & 0xff; + } + } + } + + return nOutOffset; +} + +/** + * Insert forward rep candidate + * + * @param pCompressor compression context + * @param pInWindow pointer to input data window (previously compressed bytes + bytes to compress) + * @param i input data window position whose matches are being considered + * @param nMatchOffset match offset to use as rep candidate + * @param nStartOffset current offset in input window (typically the number of previously compressed bytes) + * @param nEndOffset offset to end finding matches at (typically the size of the total input window in bytes + * @param nDepth current insertion depth + */ +static void lzsa_insert_forward_match_v2(lzsa_compressor *pCompressor, const unsigned char *pInWindow, const int i, const int nMatchOffset, const int nStartOffset, const int nEndOffset, int nDepth) { + lzsa_arrival *arrival = pCompressor->arrival + ((i - nStartOffset) << ARRIVALS_PER_POSITION_SHIFT); + const int *rle_end = (int*)pCompressor->intervals /* reuse */; + lzsa_match* visited = ((lzsa_match*)pCompressor->pos_data) - nStartOffset /* reuse */; + int j; + + for (j = 0; j < NARRIVALS_PER_POSITION_V2_BIG && arrival[j].from_slot; j++) { + int nRepOffset = arrival[j].rep_offset; + + if (nMatchOffset != nRepOffset && nRepOffset && arrival[j].rep_len >= MIN_MATCH_SIZE_V2) { + int nRepPos = arrival[j].rep_pos; + int nRepLen = arrival[j].rep_len; + + if (nRepPos > nMatchOffset && + (nRepPos + nRepLen) <= nEndOffset && + pCompressor->match[((nRepPos - nStartOffset) << MATCHES_PER_INDEX_SHIFT_V2) + NMATCHES_PER_INDEX_V2 - 1].length == 0) { + + if (visited[nRepPos].offset != nMatchOffset || visited[nRepPos].length > nRepLen) { + visited[nRepPos].offset = nMatchOffset; + visited[nRepPos].length = nRepLen; + + if (pInWindow[nRepPos] == pInWindow[nRepPos - nMatchOffset]) { + int nLen0 = rle_end[nRepPos - nMatchOffset] - (nRepPos - nMatchOffset); + int nLen1 = rle_end[nRepPos] - (nRepPos); + int nMinLen = (nLen0 < nLen1) ? nLen0 : nLen1; + + if (nMinLen >= nRepLen || !memcmp(pInWindow + nRepPos + nMinLen, pInWindow + nRepPos + nMinLen - nMatchOffset, nRepLen - nMinLen)) { + visited[nRepPos].length = 0; + + lzsa_match* fwd_match = pCompressor->match + ((nRepPos - nStartOffset) << MATCHES_PER_INDEX_SHIFT_V2); + int r; + + for (r = 0; r < NMATCHES_PER_INDEX_V2 && fwd_match[r].length >= MIN_MATCH_SIZE_V2; r++) { + if (fwd_match[r].offset == nMatchOffset) { + r = NMATCHES_PER_INDEX_V2; + break; + } + } + + if (r < NMATCHES_PER_INDEX_V2) { + int nMaxRepLen = nEndOffset - nRepPos; + if (nMaxRepLen > LCP_MAX) + nMaxRepLen = LCP_MAX; + int nCurRepLen = (nMinLen > nRepLen) ? nMinLen : nRepLen; + if (nCurRepLen > nMaxRepLen) + nCurRepLen = nMaxRepLen; + const unsigned char* pInWindowMax = pInWindow + nRepPos + nMaxRepLen; + const unsigned char* pInWindowAtRepPos = pInWindow + nRepPos + nCurRepLen; + while ((pInWindowAtRepPos + 8) < pInWindowMax && !memcmp(pInWindowAtRepPos, pInWindowAtRepPos - nMatchOffset, 8)) + pInWindowAtRepPos += 8; + while ((pInWindowAtRepPos + 4) < pInWindowMax && !memcmp(pInWindowAtRepPos, pInWindowAtRepPos - nMatchOffset, 4)) + pInWindowAtRepPos += 4; + while (pInWindowAtRepPos < pInWindowMax && pInWindowAtRepPos[0] == pInWindowAtRepPos[-nMatchOffset]) + pInWindowAtRepPos++; + + nCurRepLen = (int)(pInWindowAtRepPos - (pInWindow + nRepPos)); + fwd_match[r].offset = nMatchOffset; + fwd_match[r].length = nCurRepLen; + + if (nDepth < 9) + lzsa_insert_forward_match_v2(pCompressor, pInWindow, nRepPos, nMatchOffset, nStartOffset, nEndOffset, nDepth + 1); + } + } + } + } + } + } + } +} + +/** + * Attempt to pick optimal matches using a forward arrivals parser, so as to produce the smallest possible output that decompresses to the same input + * + * @param pCompressor compression context + * @param pInWindow pointer to input data window (previously compressed bytes + bytes to compress) + * @param pBestMatch pointer to buffer for outputting optimal matches + * @param nStartOffset current offset in input window (typically the number of previously compressed bytes) + * @param nEndOffset offset to end finding matches at (typically the size of the total input window in bytes + * @param nReduce non-zero to reduce the number of tokens when the path costs are equal, zero not to + * @param nInsertForwardReps non-zero to insert forward repmatch candidates, zero to use the previously inserted candidates + * @param nArrivalsPerPosition number of arrivals to record per input buffer position + */ +static void lzsa_optimize_forward_v2(lzsa_compressor *pCompressor, const unsigned char *pInWindow, lzsa_match *pBestMatch, const int nStartOffset, const int nEndOffset, const int nReduce, const int nInsertForwardReps, const int nArrivalsPerPosition) { + lzsa_arrival *arrival = pCompressor->arrival - (nStartOffset << ARRIVALS_PER_POSITION_SHIFT); + const int *rle_end = (int*)pCompressor->intervals /* reuse */; + lzsa_match *visited = ((lzsa_match*)pCompressor->pos_data) - nStartOffset /* reuse */; + char *nRepLenHandledMask = pCompressor->rep_handled_mask; + const int nModeSwitchPenalty = (pCompressor->flags & LZSA_FLAG_FAVOR_RATIO) ? 0 : MODESWITCH_PENALTY; + const int nMinMatchSize = pCompressor->min_match_size; + const int nDisableScore = nReduce ? 0 : (2 * BLOCK_SIZE); + const int nMaxRepInsertedLen = nReduce ? LEAVE_ALONE_MATCH_SIZE : 0; + const int nLeaveAloneMatchSize = (nArrivalsPerPosition == NARRIVALS_PER_POSITION_V2_SMALL) ? LEAVE_ALONE_MATCH_SIZE_SMALL : LEAVE_ALONE_MATCH_SIZE; + int i, j, n; + + if ((nEndOffset - nStartOffset) > BLOCK_SIZE) return; + + memset(arrival + (nStartOffset << ARRIVALS_PER_POSITION_SHIFT), 0, sizeof(lzsa_arrival) * ((nEndOffset - nStartOffset + 1) << ARRIVALS_PER_POSITION_SHIFT)); + + for (i = (nStartOffset << ARRIVALS_PER_POSITION_SHIFT); i != ((nEndOffset + 1) << ARRIVALS_PER_POSITION_SHIFT); i++) { + arrival[i].cost = 0x40000000; + } + + arrival[nStartOffset << ARRIVALS_PER_POSITION_SHIFT].from_slot = -1; + + if (nInsertForwardReps) { + memset(visited + nStartOffset, 0, (nEndOffset - nStartOffset) * sizeof(lzsa_match)); + } + + for (i = nStartOffset; i != nEndOffset; i++) { + lzsa_arrival *cur_arrival = &arrival[i << ARRIVALS_PER_POSITION_SHIFT]; + int m; + + for (j = 0; j < nArrivalsPerPosition && cur_arrival[j].from_slot; j++) { + const int nPrevCost = cur_arrival[j].cost & 0x3fffffff; + int nCodingChoiceCost = nPrevCost + 8 /* literal */; + int nNumLiterals = cur_arrival[j].num_literals + 1; + + if (nNumLiterals == LITERALS_RUN_LEN_V2) { + nCodingChoiceCost += 4; + } + else if (nNumLiterals == (LITERALS_RUN_LEN_V2 + 15)) { + nCodingChoiceCost += 8; + } + else if (nNumLiterals == 256) { + nCodingChoiceCost += 16; + } + + if (nNumLiterals == 1) + nCodingChoiceCost += nModeSwitchPenalty; + + lzsa_arrival *pDestSlots = &cur_arrival[1 << ARRIVALS_PER_POSITION_SHIFT]; + if (nCodingChoiceCost <= pDestSlots[nArrivalsPerPosition - 1].cost) { + int nRepOffset = cur_arrival[j].rep_offset; + int exists = 0; + + for (n = 0; + n < nArrivalsPerPosition && pDestSlots[n].cost < nCodingChoiceCost; + n++) { + if (pDestSlots[n].rep_offset == nRepOffset) { + exists = 1; + break; + } + } + + if (!exists) { + int nScore = cur_arrival[j].score + 1; + + for (; + n < nArrivalsPerPosition && pDestSlots[n].cost == nCodingChoiceCost && nScore >= (pDestSlots[n].score + nDisableScore); + n++) { + if (pDestSlots[n].rep_offset == nRepOffset) { + exists = 1; + break; + } + } + + if (!exists) { + if (n < nArrivalsPerPosition) { + int nn; + + for (nn = n; + nn < nArrivalsPerPosition && pDestSlots[nn].cost == nCodingChoiceCost; + nn++) { + if (pDestSlots[nn].rep_offset == nRepOffset) { + exists = 1; + break; + } + } + + if (!exists) { + int z; + + for (z = n; z < nArrivalsPerPosition - 1 && pDestSlots[z].from_slot; z++) { + if (pDestSlots[z].rep_offset == nRepOffset) + break; + } + + memmove(&pDestSlots[n + 1], + &pDestSlots[n], + sizeof(lzsa_arrival) * (z - n)); + + lzsa_arrival* pDestArrival = &pDestSlots[n]; + pDestArrival->cost = nCodingChoiceCost; + pDestArrival->from_pos = i; + pDestArrival->from_slot = j + 1; + pDestArrival->match_len = 0; + pDestArrival->num_literals = nNumLiterals; + pDestArrival->score = nScore; + pDestArrival->rep_offset = nRepOffset; + pDestArrival->rep_pos = cur_arrival[j].rep_pos; + pDestArrival->rep_len = cur_arrival[j].rep_len; + } + } + } + } + } + } + + lzsa_match *match = pCompressor->match + ((i - nStartOffset) << MATCHES_PER_INDEX_SHIFT_V2); + int nNumArrivalsForThisPos = j, nMinOverallRepLen = 0, nMaxOverallRepLen = 0; + + int nRepLenForArrival[NARRIVALS_PER_POSITION_V2_BIG]; + memset(nRepLenForArrival, 0, nArrivalsPerPosition * sizeof(int)); + + int nMaxRepLenForPos = nEndOffset - i; + if (nMaxRepLenForPos > LCP_MAX) + nMaxRepLenForPos = LCP_MAX; + const unsigned char* pInWindowStart = pInWindow + i; + const unsigned char* pInWindowMax = pInWindowStart + nMaxRepLenForPos; + + for (j = 0; j < nNumArrivalsForThisPos && (i + MIN_MATCH_SIZE_V2) <= nEndOffset; j++) { + int nRepOffset = cur_arrival[j].rep_offset; + + if (nRepOffset) { + if (i > nRepOffset) { + if (pInWindow[i] == pInWindow[i - nRepOffset]) { + const unsigned char* pInWindowAtPos; + + int nLen0 = rle_end[i - nRepOffset] - (i - nRepOffset); + int nLen1 = rle_end[i] - (i); + int nMinLen = (nLen0 < nLen1) ? nLen0 : nLen1; + + if (nMinLen > nMaxRepLenForPos) + nMinLen = nMaxRepLenForPos; + pInWindowAtPos = pInWindowStart + nMinLen; + + while ((pInWindowAtPos + 8) < pInWindowMax && !memcmp(pInWindowAtPos - nRepOffset, pInWindowAtPos, 8)) + pInWindowAtPos += 8; + while ((pInWindowAtPos + 4) < pInWindowMax && !memcmp(pInWindowAtPos - nRepOffset, pInWindowAtPos, 4)) + pInWindowAtPos += 4; + while (pInWindowAtPos < pInWindowMax && pInWindowAtPos[-nRepOffset] == pInWindowAtPos[0]) + pInWindowAtPos++; + nRepLenForArrival[j] = (int)(pInWindowAtPos - pInWindowStart); + + if (nMaxOverallRepLen < nRepLenForArrival[j]) + nMaxOverallRepLen = nRepLenForArrival[j]; + } + } + } + } + + if (!nReduce) { + memset(nRepLenHandledMask, 0, nArrivalsPerPosition * ((LCP_MAX + 1) / 8) * sizeof(char)); + } + + for (m = 0; m < NMATCHES_PER_INDEX_V2 && match[m].length; m++) { + int nMatchLen = match[m].length & 0x7fff; + int nMatchOffset = match[m].offset; + int nScorePenalty = 3 + ((match[m].length & 0x8000) >> 15); + int nNoRepmatchOffsetCost = (nMatchOffset <= 32) ? 4 : ((nMatchOffset <= 512) ? 8 : ((nMatchOffset <= (8192 + 512)) ? 12 : 16)); + int nStartingMatchLen, k; + + if ((i + nMatchLen) > nEndOffset) + nMatchLen = nEndOffset - i; + + if (nInsertForwardReps) + lzsa_insert_forward_match_v2(pCompressor, pInWindow, i, nMatchOffset, nStartOffset, nEndOffset, 0); + + int nNonRepMatchArrivalIdx = -1; + for (j = 0; j < nNumArrivalsForThisPos; j++) { + int nRepOffset = cur_arrival[j].rep_offset; + + if (nMatchOffset != nRepOffset) { + nNonRepMatchArrivalIdx = j; + break; + } + } + + int nMatchLenCost; + if (nMatchLen >= nLeaveAloneMatchSize) { + nStartingMatchLen = nMatchLen; + nMatchLenCost = 4 + 24 + 8 /* token */; + } + else { + nStartingMatchLen = nMinMatchSize; + nMatchLenCost = 0 + 8 /* token */; + } + + for (k = nStartingMatchLen; k <= nMatchLen; k++) { + if (k == (MATCH_RUN_LEN_V2 + MIN_MATCH_SIZE_V2)) { + nMatchLenCost = 4 + 8 /* token */; + } + else { + if (k == (MATCH_RUN_LEN_V2 + 15 + MIN_MATCH_SIZE_V2)) + nMatchLenCost = 4 + 8 + 8 /* token */; + else { + if (k == 256) + nMatchLenCost = 4 + 24 + 8 /* token */; + } + } + + lzsa_arrival *pDestSlots = &cur_arrival[k << ARRIVALS_PER_POSITION_SHIFT]; + + /* Insert non-repmatch candidate */ + + if (nNonRepMatchArrivalIdx >= 0) { + const int nPrevCost = cur_arrival[nNonRepMatchArrivalIdx].cost & 0x3fffffff; + int nCodingChoiceCost = nPrevCost /* the actual cost of the literals themselves accumulates up the chain */ + nMatchLenCost + nNoRepmatchOffsetCost; + + if (!cur_arrival[nNonRepMatchArrivalIdx].num_literals) + nCodingChoiceCost += nModeSwitchPenalty; + + int nScore = cur_arrival[nNonRepMatchArrivalIdx].score + nScorePenalty; + if (nCodingChoiceCost < pDestSlots[nArrivalsPerPosition - 2].cost || + (nCodingChoiceCost == pDestSlots[nArrivalsPerPosition - 2].cost && nScore < (pDestSlots[nArrivalsPerPosition - 2].score + nDisableScore))) { + int exists = 0; + + for (n = 0; + n < nArrivalsPerPosition && pDestSlots[n].cost < nCodingChoiceCost; + n++) { + if (pDestSlots[n].rep_offset == nMatchOffset) { + exists = 1; + break; + } + } + + if (!exists) { + for (; + n < nArrivalsPerPosition && pDestSlots[n].cost == nCodingChoiceCost && nScore >= (pDestSlots[n].score + nDisableScore); + n++) { + if (pDestSlots[n].rep_offset == nMatchOffset) { + exists = 1; + break; + } + } + + if (!exists) { + if (n < nArrivalsPerPosition - 1) { + int nn; + + for (nn = n; + nn < nArrivalsPerPosition && pDestSlots[nn].cost == nCodingChoiceCost; + nn++) { + if (pDestSlots[nn].rep_offset == nMatchOffset && + (!nInsertForwardReps || pDestSlots[nn].rep_pos >= i || + pDestSlots[nArrivalsPerPosition - 1].from_slot)) { + exists = 1; + break; + } + } + + if (!exists) { + int z; + + for (z = n; z < nArrivalsPerPosition - 1 && pDestSlots[z].from_slot; z++) { + if (pDestSlots[z].rep_offset == nMatchOffset) + break; + } + + if (z == (nArrivalsPerPosition - 1) && pDestSlots[z].from_slot && pDestSlots[z].match_len < MIN_MATCH_SIZE_V2) + z--; + + memmove(&pDestSlots[n + 1], + &pDestSlots[n], + sizeof(lzsa_arrival) * (z - n)); + + lzsa_arrival* pDestArrival = &pDestSlots[n]; + pDestArrival->cost = nCodingChoiceCost; + pDestArrival->from_pos = i; + pDestArrival->from_slot = nNonRepMatchArrivalIdx + 1; + pDestArrival->match_len = k; + pDestArrival->num_literals = 0; + pDestArrival->score = nScore; + pDestArrival->rep_offset = nMatchOffset; + pDestArrival->rep_pos = i; + pDestArrival->rep_len = k; + } + } + } + } + } + } + + /* Insert repmatch candidates */ + + if (k > nMinOverallRepLen && k <= nMaxOverallRepLen) { + for (j = 0; j < nNumArrivalsForThisPos; j++) { + int nMaskOffset = (j << 7) + (k >> 3); + if (nRepLenForArrival[j] >= k && (nReduce || !(nRepLenHandledMask[nMaskOffset] & (1 << (k & 7))))) { + const int nPrevCost = cur_arrival[j].cost & 0x3fffffff; + int nRepCodingChoiceCost = nPrevCost /* the actual cost of the literals themselves accumulates up the chain */ + nMatchLenCost; + int nScore = cur_arrival[j].score + 2; + + if (nRepCodingChoiceCost < pDestSlots[nArrivalsPerPosition - 1].cost || + (nRepCodingChoiceCost == pDestSlots[nArrivalsPerPosition - 1].cost && nScore < (pDestSlots[nArrivalsPerPosition - 1].score + nDisableScore))) { + int nRepOffset = cur_arrival[j].rep_offset; + int exists = 0; + + for (n = 0; + n < nArrivalsPerPosition && pDestSlots[n].cost < nRepCodingChoiceCost; + n++) { + if (pDestSlots[n].rep_offset == nRepOffset) { + exists = 1; + if (!nReduce) + nRepLenHandledMask[nMaskOffset] |= 1 << (k & 7); + break; + } + } + + if (!exists) { + for (; + n < nArrivalsPerPosition && pDestSlots[n].cost == nRepCodingChoiceCost && nScore >= (pDestSlots[n].score + nDisableScore); + n++) { + if (pDestSlots[n].rep_offset == nRepOffset) { + exists = 1; + break; + } + } + + if (!exists) { + if (n < nArrivalsPerPosition) { + int nn; + + for (nn = n; + nn < nArrivalsPerPosition && pDestSlots[nn].cost == nRepCodingChoiceCost; + nn++) { + if (pDestSlots[nn].rep_offset == nRepOffset) { + exists = 1; + break; + } + } + + if (!exists) { + int z; + + for (z = n; z < nArrivalsPerPosition - 1 && pDestSlots[z].from_slot; z++) { + if (pDestSlots[z].rep_offset == nRepOffset) + break; + } + + memmove(&pDestSlots[n + 1], + &pDestSlots[n], + sizeof(lzsa_arrival) * (z - n)); + + lzsa_arrival* pDestArrival = &pDestSlots[n]; + pDestArrival->cost = nRepCodingChoiceCost; + pDestArrival->from_pos = i; + pDestArrival->from_slot = j + 1; + pDestArrival->match_len = k; + pDestArrival->num_literals = 0; + pDestArrival->score = nScore; + pDestArrival->rep_offset = nRepOffset; + pDestArrival->rep_pos = i; + pDestArrival->rep_len = k; + } + } + } + } + } + else { + break; + } + } + } + + if (k < nMaxRepInsertedLen) + nMinOverallRepLen = k; + } + } + + if (nMatchLen >= LCP_MAX && ((m + 1) >= NMATCHES_PER_INDEX_V2 || match[m + 1].length < LCP_MAX)) + break; + } + } + + lzsa_arrival *end_arrival = &arrival[(i << ARRIVALS_PER_POSITION_SHIFT) + 0]; + + while (end_arrival->from_slot > 0 && end_arrival->from_pos >= 0) { + if (end_arrival->from_pos >= nEndOffset) return; + pBestMatch[end_arrival->from_pos].length = end_arrival->match_len; + if (end_arrival->match_len) + pBestMatch[end_arrival->from_pos].offset = end_arrival->rep_offset; + else + pBestMatch[end_arrival->from_pos].offset = 0; + end_arrival = &arrival[(end_arrival->from_pos << ARRIVALS_PER_POSITION_SHIFT) + (end_arrival->from_slot - 1)]; + } +} + +/** + * Attempt to minimize the number of commands issued in the compressed data block, in order to speed up decompression without + * impacting the compression ratio + * + * @param pCompressor compression context + * @param pInWindow pointer to input data window (previously compressed bytes + bytes to compress) + * @param pBestMatch optimal matches to evaluate and update + * @param nStartOffset current offset in input window (typically the number of previously compressed bytes) + * @param nEndOffset offset to end finding matches at (typically the size of the total input window in bytes + * + * @return non-zero if the number of tokens was reduced, 0 if it wasn't + */ +static int lzsa_optimize_command_count_v2(lzsa_compressor *pCompressor, const unsigned char *pInWindow, lzsa_match *pBestMatch, const int nStartOffset, const int nEndOffset) { + int i; + int nNumLiterals = 0; + int nPrevRepMatchOffset = 0; + int nRepMatchOffset = 0; + int nRepMatchLen = 0; + int nRepIndex = 0; + int nDidReduce = 0; + + for (i = nStartOffset; i < nEndOffset; ) { + lzsa_match *pMatch = pBestMatch + i; + + if (pMatch->length == 0 && + (i + 1) < nEndOffset && + pBestMatch[i + 1].length >= MIN_MATCH_SIZE_V2 && + pBestMatch[i + 1].length < MAX_VARLEN && + pBestMatch[i + 1].offset && + i >= pBestMatch[i + 1].offset && + (i + pBestMatch[i + 1].length + 1) <= nEndOffset && + !memcmp(pInWindow + i - (pBestMatch[i + 1].offset), pInWindow + i, pBestMatch[i + 1].length + 1)) { + int nCurLenSize = lzsa_get_match_varlen_size_v2(pBestMatch[i + 1].length - MIN_MATCH_SIZE_V2); + int nReducedLenSize = lzsa_get_match_varlen_size_v2(pBestMatch[i + 1].length + 1 - MIN_MATCH_SIZE_V2); + + if ((nReducedLenSize - nCurLenSize) <= 8) { + /* Merge */ + pBestMatch[i].length = pBestMatch[i + 1].length + 1; + pBestMatch[i].offset = pBestMatch[i + 1].offset; + pBestMatch[i + 1].length = 0; + pBestMatch[i + 1].offset = 0; + nDidReduce = 1; + continue; + } + } + + if (pMatch->length >= MIN_MATCH_SIZE_V2) { + if ((i + pMatch->length) < nEndOffset /* Don't consider the last match in the block, we can only reduce a match inbetween other tokens */) { + int nNextIndex = i + pMatch->length; + int nNextLiterals = 0; + + while (nNextIndex < nEndOffset && pBestMatch[nNextIndex].length < MIN_MATCH_SIZE_V2) { + nNextLiterals++; + nNextIndex++; + } + + if (nNextIndex < nEndOffset && pBestMatch[nNextIndex].length >= MIN_MATCH_SIZE_V2) { + /* This command is a match, is followed by 'nNextLiterals' literals and then by another match */ + + if (nRepMatchOffset && pMatch->offset != nRepMatchOffset && (pBestMatch[nNextIndex].offset != pMatch->offset || pBestMatch[nNextIndex].offset == nRepMatchOffset || + ((pMatch->offset <= 32) ? 4 : ((pMatch->offset <= 512) ? 8 : ((pMatch->offset <= (8192 + 512)) ? 12 : 16))) > + ((pBestMatch[nNextIndex].offset <= 32) ? 4 : ((pBestMatch[nNextIndex].offset <= 512) ? 8 : ((pBestMatch[nNextIndex].offset <= (8192 + 512)) ? 12 : 16))))) { + /* Check if we can change the current match's offset to be the same as the previous match's offset, and get an extra repmatch. This will occur when + * matching large regions of identical bytes for instance, where there are too many offsets to be considered by the parser, and when not compressing to favor the + * ratio (the forward arrivals parser already has this covered). */ + if (i > nRepMatchOffset && + (i - nRepMatchOffset + pMatch->length) <= nEndOffset && + !memcmp(pInWindow + i - nRepMatchOffset, pInWindow + i - pMatch->offset, pMatch->length)) { + pMatch->offset = nRepMatchOffset; + nDidReduce = 1; + } + } + + if (pBestMatch[nNextIndex].offset && pMatch->offset != pBestMatch[nNextIndex].offset && nRepMatchOffset != pBestMatch[nNextIndex].offset) { + /* Otherwise, try to gain a match forward as well */ + if (i > pBestMatch[nNextIndex].offset && (i - pBestMatch[nNextIndex].offset + pMatch->length) <= nEndOffset) { + int nMaxLen = 0; + while (nMaxLen < pMatch->length && pInWindow[i - pBestMatch[nNextIndex].offset + nMaxLen] == pInWindow[i - pMatch->offset + nMaxLen]) + nMaxLen++; + if (nMaxLen >= pMatch->length) { + /* Replace */ + pMatch->offset = pBestMatch[nNextIndex].offset; + nDidReduce = 1; + } + else if (nMaxLen >= 2 && pMatch->offset != nRepMatchOffset) { + int nPartialSizeBefore, nPartialSizeAfter; + + nPartialSizeBefore = lzsa_get_match_varlen_size_v2(pMatch->length - MIN_MATCH_SIZE_V2); + nPartialSizeBefore += (pMatch->offset <= 32) ? 4 : ((pMatch->offset <= 512) ? 8 : ((pMatch->offset <= (8192 + 512)) ? 12 : 16)); + nPartialSizeBefore += lzsa_get_literals_varlen_size_v2(nNextLiterals); + + nPartialSizeAfter = lzsa_get_match_varlen_size_v2(nMaxLen - MIN_MATCH_SIZE_V2); + nPartialSizeAfter += lzsa_get_literals_varlen_size_v2(nNextLiterals + (pMatch->length - nMaxLen)) + ((pMatch->length - nMaxLen) << 3); + + if (nPartialSizeAfter < nPartialSizeBefore) { + int j; + + /* We gain a repmatch that is shorter than the original match as this is the best we can do, so it is followed by extra literals, but + * we have calculated that this is shorter */ + pMatch->offset = pBestMatch[nNextIndex].offset; + for (j = nMaxLen; j < pMatch->length; j++) { + pBestMatch[i + j].length = 0; + } + pMatch->length = nMaxLen; + nDidReduce = 1; + } + } + } + } + + if (pMatch->length < 9 /* Don't waste time considering large matches, they will always win over literals */) { + /* Calculate this command's current cost (excluding 'nNumLiterals' bytes) */ + + int nCurCommandSize = 8 /* token */ + lzsa_get_literals_varlen_size_v2(nNumLiterals) + lzsa_get_match_varlen_size_v2(pMatch->length - MIN_MATCH_SIZE_V2); + if (pMatch->offset != nRepMatchOffset) + nCurCommandSize += (pMatch->offset <= 32) ? 4 : ((pMatch->offset <= 512) ? 8 : ((pMatch->offset <= (8192 + 512)) ? 12 : 16)); + + /* Calculate the next command's current cost */ + int nNextCommandSize = 8 /* token */ + lzsa_get_literals_varlen_size_v2(nNextLiterals) + /* (nNextLiterals << 3) + */ lzsa_get_match_varlen_size_v2(pBestMatch[nNextIndex].length - MIN_MATCH_SIZE_V2); + if (pBestMatch[nNextIndex].offset != pMatch->offset) + nNextCommandSize += (pBestMatch[nNextIndex].offset <= 32) ? 4 : ((pBestMatch[nNextIndex].offset <= 512) ? 8 : ((pBestMatch[nNextIndex].offset <= (8192 + 512)) ? 12 : 16)); + + int nOriginalCombinedCommandSize = nCurCommandSize + nNextCommandSize; + + /* Calculate the cost of replacing this match command by literals + the next command with the cost of encoding these literals (excluding 'nNumLiterals' bytes) */ + int nReducedCommandSize = (pMatch->length << 3) + 8 /* token */ + lzsa_get_literals_varlen_size_v2(nNumLiterals + pMatch->length + nNextLiterals) + /* (nNextLiterals << 3) + */ lzsa_get_match_varlen_size_v2(pBestMatch[nNextIndex].length - MIN_MATCH_SIZE_V2); + if (pBestMatch[nNextIndex].offset != nRepMatchOffset) + nReducedCommandSize += (pBestMatch[nNextIndex].offset <= 32) ? 4 : ((pBestMatch[nNextIndex].offset <= 512) ? 8 : ((pBestMatch[nNextIndex].offset <= (8192 + 512)) ? 12 : 16)); + + int nReplaceRepOffset = 0; + if (nRepMatchOffset && nRepMatchOffset != nPrevRepMatchOffset && nRepMatchLen >= MIN_MATCH_SIZE_V2 && nRepMatchOffset != pBestMatch[nNextIndex].offset && nRepIndex > pBestMatch[nNextIndex].offset && + (nRepIndex - pBestMatch[nNextIndex].offset + nRepMatchLen) <= nEndOffset && + !memcmp(pInWindow + nRepIndex - nRepMatchOffset, pInWindow + nRepIndex - pBestMatch[nNextIndex].offset, nRepMatchLen)) { + /* Replacing this match command by literals would let us create a repmatch */ + nReplaceRepOffset = 1; + nReducedCommandSize -= (nRepMatchOffset <= 32) ? 4 : ((nRepMatchOffset <= 512) ? 8 : ((nRepMatchOffset <= (8192 + 512)) ? 12 : 16)); + } + + if (nOriginalCombinedCommandSize >= nReducedCommandSize) { + /* Reduce */ + int nMatchLen = pMatch->length; + int j; + + for (j = 0; j < nMatchLen; j++) { + pBestMatch[i + j].length = 0; + } + + nDidReduce = 1; + + if (nReplaceRepOffset) { + pBestMatch[nRepIndex].offset = pBestMatch[nNextIndex].offset; + nRepMatchOffset = pBestMatch[nNextIndex].offset; + } + continue; + } + } + } + } + + if ((i + pMatch->length) <= nEndOffset && pMatch->offset > 0 && pMatch->length >= MIN_MATCH_SIZE_V2 && + pBestMatch[i + pMatch->length].offset > 0 && + pBestMatch[i + pMatch->length].length >= MIN_MATCH_SIZE_V2 && + (pMatch->length + pBestMatch[i + pMatch->length].length) >= LEAVE_ALONE_MATCH_SIZE && + (pMatch->length + pBestMatch[i + pMatch->length].length) <= MAX_VARLEN && + (i + pMatch->length) > pMatch->offset && + (i + pMatch->length) > pBestMatch[i + pMatch->length].offset && + (i + pMatch->length + pBestMatch[i + pMatch->length].length) <= nEndOffset && + !memcmp(pInWindow + i - pMatch->offset + pMatch->length, + pInWindow + i + pMatch->length - pBestMatch[i + pMatch->length].offset, + pBestMatch[i + pMatch->length].length)) { + + int nNextIndex = i + pMatch->length; + + while (nNextIndex < nEndOffset && pBestMatch[nNextIndex].length < MIN_MATCH_SIZE_V2) { + nNextIndex++; + } + + int nNextOffset; + if (nNextIndex < nEndOffset) + nNextOffset = pBestMatch[nNextIndex].offset; + else + nNextOffset = 0; + + int nCurPartialSize = lzsa_get_match_varlen_size_v2(pMatch->length - MIN_MATCH_SIZE_V2); + + nCurPartialSize += 8 /* token */ + /* lzsa_get_literals_varlen_size_v2(0) + */ lzsa_get_match_varlen_size_v2(pBestMatch[i + pMatch->length].length - MIN_MATCH_SIZE_V2); + if (pBestMatch[i + pMatch->length].offset != pMatch->offset) + nCurPartialSize += (pBestMatch[i + pMatch->length].offset <= 32) ? 4 : ((pBestMatch[i + pMatch->length].offset <= 512) ? 8 : ((pBestMatch[i + pMatch->length].offset <= (8192 + 512)) ? 12 : 16)); + + if (nNextOffset != pBestMatch[i + pMatch->length].offset) + nCurPartialSize += (nNextOffset <= 32) ? 4 : ((nNextOffset <= 512) ? 8 : ((nNextOffset <= (8192 + 512)) ? 12 : 16)); + + int nReducedPartialSize = lzsa_get_match_varlen_size_v2(pMatch->length + pBestMatch[i + pMatch->length].length - MIN_MATCH_SIZE_V2); + + if (nNextOffset != pMatch->offset) + nReducedPartialSize += (nNextOffset <= 32) ? 4 : ((nNextOffset <= 512) ? 8 : ((nNextOffset <= (8192 + 512)) ? 12 : 16)); + + if (nCurPartialSize >= nReducedPartialSize) { + int nMatchLen = pMatch->length; + + /* Join */ + + pMatch->length += pBestMatch[i + nMatchLen].length; + pBestMatch[i + nMatchLen].offset = 0; + pBestMatch[i + nMatchLen].length = -1; + nDidReduce = 1; + continue; + } + } + + nPrevRepMatchOffset = nRepMatchOffset; + nRepMatchOffset = pMatch->offset; + nRepMatchLen = pMatch->length; + nRepIndex = i; + + i += pMatch->length; + nNumLiterals = 0; + } + else { + nNumLiterals++; + i++; + } + } + + return nDidReduce; +} + +/** + * Get compressed data block size + * + * @param pCompressor compression context + * @param pBestMatch optimal matches to emit + * @param nStartOffset current offset in input window (typically the number of previously compressed bytes) + * @param nEndOffset offset to end finding matches at (typically the size of the total input window in bytes + * + * @return size of compressed data that will be written to output buffer + */ +static int lzsa_get_compressed_size_v2(lzsa_compressor *pCompressor, lzsa_match *pBestMatch, const int nStartOffset, const int nEndOffset) { + int i; + int nNumLiterals = 0; + int nRepMatchOffset = 0; + int nCompressedSize = 0; + + for (i = nStartOffset; i < nEndOffset; ) { + const lzsa_match *pMatch = pBestMatch + i; + + if (pMatch->length >= MIN_MATCH_SIZE_V2) { + int nMatchOffset = pMatch->offset; + int nMatchLen = pMatch->length; + int nEncodedMatchLen = nMatchLen - MIN_MATCH_SIZE_V2; + int nOffsetSize; + + if (nMatchOffset == nRepMatchOffset) { + nOffsetSize = 0; + } + else { + if (nMatchOffset <= 32) { + nOffsetSize = 4; + } + else if (nMatchOffset <= 512) { + nOffsetSize = 8; + } + else if (nMatchOffset <= (8192 + 512)) { + nOffsetSize = 12; + } + else { + nOffsetSize = 16; + } + } + + int nCommandSize = 8 /* token */ + lzsa_get_literals_varlen_size_v2(nNumLiterals) + (nNumLiterals << 3) + nOffsetSize /* match offset */ + lzsa_get_match_varlen_size_v2(nEncodedMatchLen); + nCompressedSize += nCommandSize; + + nNumLiterals = 0; + nRepMatchOffset = nMatchOffset; + i += nMatchLen; + } + else { + nNumLiterals++; + i++; + } + } + + { + int nCommandSize = 8 /* token */ + lzsa_get_literals_varlen_size_v2(nNumLiterals) + (nNumLiterals << 3); + + nCompressedSize += nCommandSize; + nNumLiterals = 0; + } + + if (pCompressor->flags & LZSA_FLAG_RAW_BLOCK) { + nCompressedSize += (8 + 4); + } + + return nCompressedSize; +} + +/** + * Emit block of compressed data + * + * @param pCompressor compression context + * @param pBestMatch optimal matches to emit + * @param pInWindow pointer to input data window (previously compressed bytes + bytes to compress) + * @param nStartOffset current offset in input window (typically the number of previously compressed bytes) + * @param nEndOffset offset to end finding matches at (typically the size of the total input window in bytes + * @param pOutData pointer to output buffer + * @param nMaxOutDataSize maximum size of output buffer, in bytes + * + * @return size of compressed data in output buffer, or -1 if the data is uncompressible + */ +static int lzsa_write_block_v2(lzsa_compressor *pCompressor, lzsa_match *pBestMatch, const unsigned char *pInWindow, const int nStartOffset, const int nEndOffset, unsigned char *pOutData, const int nMaxOutDataSize) { + int i; + int nNumLiterals = 0; + int nInFirstLiteralOffset = 0; + int nOutOffset = 0; + int nCurNibbleOffset = -1; + int nRepMatchOffset = 0; + + for (i = nStartOffset; i < nEndOffset; ) { + const lzsa_match *pMatch = pBestMatch + i; + + if (pMatch->length >= MIN_MATCH_SIZE_V2) { + int nMatchOffset = pMatch->offset; + int nMatchLen = pMatch->length; + int nEncodedMatchLen = nMatchLen - MIN_MATCH_SIZE_V2; + int nTokenLiteralsLen = (nNumLiterals >= LITERALS_RUN_LEN_V2) ? LITERALS_RUN_LEN_V2 : nNumLiterals; + int nTokenMatchLen = (nEncodedMatchLen >= MATCH_RUN_LEN_V2) ? MATCH_RUN_LEN_V2 : nEncodedMatchLen; + int nTokenOffsetMode; + int nOffsetSize; + + if (nMatchOffset == nRepMatchOffset) { + nTokenOffsetMode = 0xe0; + nOffsetSize = 0; + } + else { + if (nMatchOffset <= 32) { + nTokenOffsetMode = 0x00 | ((((-nMatchOffset) & 0x01) << 5) ^ 0x20); + nOffsetSize = 4; + } + else if (nMatchOffset <= 512) { + nTokenOffsetMode = 0x40 | ((((-nMatchOffset) & 0x100) >> 3) ^ 0x20); + nOffsetSize = 8; + } + else if (nMatchOffset <= (8192 + 512)) { + nTokenOffsetMode = 0x80 | ((((-(nMatchOffset - 512)) & 0x0100) >> 3) ^ 0x20); + nOffsetSize = 12; + } + else { + nTokenOffsetMode = 0xc0; + nOffsetSize = 16; + } + } + + int nCommandSize = 8 /* token */ + lzsa_get_literals_varlen_size_v2(nNumLiterals) + (nNumLiterals << 3) + nOffsetSize /* match offset */ + lzsa_get_match_varlen_size_v2(nEncodedMatchLen); + + if ((nOutOffset + ((nCommandSize + 7) >> 3)) > nMaxOutDataSize) + return -1; + if (nMatchOffset < MIN_OFFSET || nMatchOffset > MAX_OFFSET) + return -1; + + pOutData[nOutOffset++] = nTokenOffsetMode | (nTokenLiteralsLen << 3) | nTokenMatchLen; + nOutOffset = lzsa_write_literals_varlen_v2(pOutData, nOutOffset, nMaxOutDataSize, &nCurNibbleOffset, nNumLiterals); + if (nOutOffset < 0) return -1; + + if (nNumLiterals < pCompressor->stats.min_literals || pCompressor->stats.min_literals == -1) + pCompressor->stats.min_literals = nNumLiterals; + if (nNumLiterals > pCompressor->stats.max_literals) + pCompressor->stats.max_literals = nNumLiterals; + pCompressor->stats.total_literals += nNumLiterals; + pCompressor->stats.literals_divisor++; + + if (nNumLiterals != 0) { + memcpy(pOutData + nOutOffset, pInWindow + nInFirstLiteralOffset, nNumLiterals); + nOutOffset += nNumLiterals; + nNumLiterals = 0; + } + + if (nTokenOffsetMode == 0x00 || nTokenOffsetMode == 0x20) { + nOutOffset = lzsa_write_nibble_v2(pOutData, nOutOffset, nMaxOutDataSize, &nCurNibbleOffset, ((-nMatchOffset) & 0x1e) >> 1); + if (nOutOffset < 0) return -1; + } + else if (nTokenOffsetMode == 0x40 || nTokenOffsetMode == 0x60) { + pOutData[nOutOffset++] = (-nMatchOffset) & 0xff; + } + else if (nTokenOffsetMode == 0x80 || nTokenOffsetMode == 0xa0) { + nOutOffset = lzsa_write_nibble_v2(pOutData, nOutOffset, nMaxOutDataSize, &nCurNibbleOffset, ((-(nMatchOffset - 512)) >> 9) & 0x0f); + if (nOutOffset < 0) return -1; + pOutData[nOutOffset++] = (-(nMatchOffset - 512)) & 0xff; + } + else if (nTokenOffsetMode == 0xc0) { + pOutData[nOutOffset++] = (-nMatchOffset) >> 8; + pOutData[nOutOffset++] = (-nMatchOffset) & 0xff; + } + + if (nMatchOffset == nRepMatchOffset) + pCompressor->stats.num_rep_offsets++; + + nRepMatchOffset = nMatchOffset; + + nOutOffset = lzsa_write_match_varlen_v2(pOutData, nOutOffset, nMaxOutDataSize, &nCurNibbleOffset, nEncodedMatchLen); + if (nOutOffset < 0) return -1; + + if (nMatchOffset < pCompressor->stats.min_offset || pCompressor->stats.min_offset == -1) + pCompressor->stats.min_offset = nMatchOffset; + if (nMatchOffset > pCompressor->stats.max_offset) + pCompressor->stats.max_offset = nMatchOffset; + pCompressor->stats.total_offsets += nMatchOffset; + + if (nMatchLen < pCompressor->stats.min_match_len || pCompressor->stats.min_match_len == -1) + pCompressor->stats.min_match_len = nMatchLen; + if (nMatchLen > pCompressor->stats.max_match_len) + pCompressor->stats.max_match_len = nMatchLen; + pCompressor->stats.total_match_lens += nMatchLen; + pCompressor->stats.match_divisor++; + + if (nMatchOffset == 1) { + if (nMatchLen < pCompressor->stats.min_rle1_len || pCompressor->stats.min_rle1_len == -1) + pCompressor->stats.min_rle1_len = nMatchLen; + if (nMatchLen > pCompressor->stats.max_rle1_len) + pCompressor->stats.max_rle1_len = nMatchLen; + pCompressor->stats.total_rle1_lens += nMatchLen; + pCompressor->stats.rle1_divisor++; + } + else if (nMatchOffset == 2) { + if (nMatchLen < pCompressor->stats.min_rle2_len || pCompressor->stats.min_rle2_len == -1) + pCompressor->stats.min_rle2_len = nMatchLen; + if (nMatchLen > pCompressor->stats.max_rle2_len) + pCompressor->stats.max_rle2_len = nMatchLen; + pCompressor->stats.total_rle2_lens += nMatchLen; + pCompressor->stats.rle2_divisor++; + } + + i += nMatchLen; + + if (pCompressor->flags & LZSA_FLAG_RAW_BLOCK) { + int nCurSafeDist = (i - nStartOffset) - nOutOffset; + if (nCurSafeDist >= 0 && pCompressor->safe_dist < nCurSafeDist) + pCompressor->safe_dist = nCurSafeDist; + } + + pCompressor->num_commands++; + } + else { + if (nNumLiterals == 0) + nInFirstLiteralOffset = i; + nNumLiterals++; + i++; + } + } + + { + int nTokenLiteralsLen = (nNumLiterals >= LITERALS_RUN_LEN_V2) ? LITERALS_RUN_LEN_V2 : nNumLiterals; + int nCommandSize = 8 /* token */ + lzsa_get_literals_varlen_size_v2(nNumLiterals) + (nNumLiterals << 3); + + if ((nOutOffset + ((nCommandSize + 7) >> 3)) > nMaxOutDataSize) + return -1; + + if (pCompressor->flags & LZSA_FLAG_RAW_BLOCK) + pOutData[nOutOffset++] = (nTokenLiteralsLen << 3) | 0xe7; + else + pOutData[nOutOffset++] = (nTokenLiteralsLen << 3) | 0x00; + nOutOffset = lzsa_write_literals_varlen_v2(pOutData, nOutOffset, nMaxOutDataSize, &nCurNibbleOffset, nNumLiterals); + if (nOutOffset < 0) return -1; + + if (nNumLiterals < pCompressor->stats.min_literals || pCompressor->stats.min_literals == -1) + pCompressor->stats.min_literals = nNumLiterals; + if (nNumLiterals > pCompressor->stats.max_literals) + pCompressor->stats.max_literals = nNumLiterals; + pCompressor->stats.total_literals += nNumLiterals; + pCompressor->stats.literals_divisor++; + + if (nNumLiterals != 0) { + memcpy(pOutData + nOutOffset, pInWindow + nInFirstLiteralOffset, nNumLiterals); + nOutOffset += nNumLiterals; + nNumLiterals = 0; + } + + if (pCompressor->flags & LZSA_FLAG_RAW_BLOCK) { + int nCurSafeDist = (i - nStartOffset) - nOutOffset; + if (nCurSafeDist >= 0 && pCompressor->safe_dist < nCurSafeDist) + pCompressor->safe_dist = nCurSafeDist; + } + + pCompressor->num_commands++; + } + + if (pCompressor->flags & LZSA_FLAG_RAW_BLOCK) { + /* Emit EOD marker for raw block */ + + if (nOutOffset >= nMaxOutDataSize) + return -1; + + nOutOffset = lzsa_write_nibble_v2(pOutData, nOutOffset, nMaxOutDataSize, &nCurNibbleOffset, 15); /* Extended match length nibble */ + if (nOutOffset < 0) return -1; + + if ((nOutOffset + 1) > nMaxOutDataSize) + return -1; + + pOutData[nOutOffset++] = 232; /* EOD match length byte */ + } + + if (nCurNibbleOffset != -1) { + nOutOffset = lzsa_write_nibble_v2(pOutData, nOutOffset, nMaxOutDataSize, &nCurNibbleOffset, 0); + if (nOutOffset < 0 || nCurNibbleOffset != -1) + return -1; + } + + return nOutOffset; +} + +/** + * Emit raw block of uncompressible data + * + * @param pCompressor compression context + * @param pInWindow pointer to input data window (previously compressed bytes + bytes to compress) + * @param nStartOffset current offset in input window (typically the number of previously compressed bytes) + * @param nEndOffset offset to end finding matches at (typically the size of the total input window in bytes + * @param pOutData pointer to output buffer + * @param nMaxOutDataSize maximum size of output buffer, in bytes + * + * @return size of compressed data in output buffer, or -1 if the data is uncompressible + */ +static int lzsa_write_raw_uncompressed_block_v2(lzsa_compressor *pCompressor, const unsigned char *pInWindow, const int nStartOffset, const int nEndOffset, unsigned char *pOutData, const int nMaxOutDataSize) { + int nCurNibbleOffset = -1; + int nNumLiterals = nEndOffset - nStartOffset; + int nTokenLiteralsLen = (nNumLiterals >= LITERALS_RUN_LEN_V2) ? LITERALS_RUN_LEN_V2 : nNumLiterals; + int nOutOffset = 0; + + int nCommandSize = 8 /* token */ + lzsa_get_literals_varlen_size_v2(nNumLiterals) + (nNumLiterals << 3) + 4 + 8; + if ((nOutOffset + ((nCommandSize + 7) >> 3)) > nMaxOutDataSize) + return -1; + + pCompressor->num_commands = 0; + pOutData[nOutOffset++] = (nTokenLiteralsLen << 3) | 0xe7; + + nOutOffset = lzsa_write_literals_varlen_v2(pOutData, nOutOffset, nMaxOutDataSize, &nCurNibbleOffset, nNumLiterals); + if (nOutOffset < 0) return -1; + + if (nNumLiterals != 0) { + memcpy(pOutData + nOutOffset, pInWindow + nStartOffset, nNumLiterals); + nOutOffset += nNumLiterals; + nNumLiterals = 0; + } + + /* Emit EOD marker for raw block */ + + nOutOffset = lzsa_write_nibble_v2(pOutData, nOutOffset, nMaxOutDataSize, &nCurNibbleOffset, 15); /* Extended match length nibble */ + if (nOutOffset < 0) return -1; + + if ((nOutOffset + 1) > nMaxOutDataSize) + return -1; + + pOutData[nOutOffset++] = 232; /* EOD match length byte */ + + pCompressor->num_commands++; + + if (nCurNibbleOffset != -1) { + nOutOffset = lzsa_write_nibble_v2(pOutData, nOutOffset, nMaxOutDataSize, &nCurNibbleOffset, 0); + if (nOutOffset < 0 || nCurNibbleOffset != -1) + return -1; + } + + return nOutOffset; +} + +/** + * Select the most optimal matches, reduce the token count if possible, and then emit a block of compressed LZSA2 data + * + * @param pCompressor compression context + * @param pInWindow pointer to input data window (previously compressed bytes + bytes to compress) + * @param nPreviousBlockSize number of previously compressed bytes (or 0 for none) + * @param nInDataSize number of input bytes to compress + * @param pOutData pointer to output buffer + * @param nMaxOutDataSize maximum size of output buffer, in bytes + * + * @return size of compressed data in output buffer, or -1 if the data is uncompressible + */ +int lzsa_optimize_and_write_block_v2(lzsa_compressor *pCompressor, const unsigned char *pInWindow, const int nPreviousBlockSize, const int nInDataSize, unsigned char *pOutData, const int nMaxOutDataSize) { + int nResult, nBaseCompressedSize; + int nArrivalsPerPosition = (nInDataSize < 65536) ? NARRIVALS_PER_POSITION_V2_BIG : NARRIVALS_PER_POSITION_V2_SMALL; + int *rle_end = (int*)pCompressor->intervals /* reuse */; + int i; + + i = 0; + while (i < (nPreviousBlockSize + nInDataSize)) { + int nRangeStartIdx = i; + unsigned char c = pInWindow[nRangeStartIdx]; + do { + i++; + } while (i < (nPreviousBlockSize + nInDataSize) && pInWindow[i] == c); + while (nRangeStartIdx < i) { + rle_end[nRangeStartIdx++] = i; + } + } + + /* Compress optimally without breaking ties in favor of less tokens */ + + memset(pCompressor->best_match, 0, BLOCK_SIZE * sizeof(lzsa_match)); + lzsa_optimize_forward_v2(pCompressor, pInWindow, pCompressor->best_match - nPreviousBlockSize, nPreviousBlockSize, nPreviousBlockSize + nInDataSize, 0 /* reduce */, (nInDataSize < 65536) ? 1 : 0 /* insert forward reps */, nArrivalsPerPosition); + + int nDidReduce; + int nPasses = 0; + do { + nDidReduce = lzsa_optimize_command_count_v2(pCompressor, pInWindow, pCompressor->best_match - nPreviousBlockSize, nPreviousBlockSize, nPreviousBlockSize + nInDataSize); + nPasses++; + } while (nDidReduce && nPasses < 20); + + nBaseCompressedSize = lzsa_get_compressed_size_v2(pCompressor, pCompressor->best_match - nPreviousBlockSize, nPreviousBlockSize, nPreviousBlockSize + nInDataSize); + lzsa_match *pBestMatch = pCompressor->best_match - nPreviousBlockSize; + + if (nBaseCompressedSize > 0 && nInDataSize < 65536) { + int nReducedCompressedSize; + + /* Compress optimally and do break ties in favor of less tokens */ + memset(pCompressor->improved_match, 0, BLOCK_SIZE * sizeof(lzsa_match)); + lzsa_optimize_forward_v2(pCompressor, pInWindow, pCompressor->improved_match - nPreviousBlockSize, nPreviousBlockSize, nPreviousBlockSize + nInDataSize, 1 /* reduce */, 0 /* use forward reps */, nArrivalsPerPosition); + + nPasses = 0; + do { + nDidReduce = lzsa_optimize_command_count_v2(pCompressor, pInWindow, pCompressor->improved_match - nPreviousBlockSize, nPreviousBlockSize, nPreviousBlockSize + nInDataSize); + nPasses++; + } while (nDidReduce && nPasses < 20); + + nReducedCompressedSize = lzsa_get_compressed_size_v2(pCompressor, pCompressor->improved_match - nPreviousBlockSize, nPreviousBlockSize, nPreviousBlockSize + nInDataSize); + if (nReducedCompressedSize > 0 && nReducedCompressedSize <= nBaseCompressedSize) { + const int nEndOffset = nPreviousBlockSize + nInDataSize; + int nSupplementedCompressedSize; + + /* Pick the parse with the reduced number of tokens as it didn't negatively affect the size */ + pBestMatch = pCompressor->improved_match - nPreviousBlockSize; + + int* first_offset_for_byte = pCompressor->first_offset_for_byte; + int* next_offset_for_pos = pCompressor->next_offset_for_pos; + int nPosition; + + /* Supplement small matches */ + + memset(first_offset_for_byte, 0xff, sizeof(int) * 65536); + memset(next_offset_for_pos, 0xff, sizeof(int) * nInDataSize); + + for (nPosition = nPreviousBlockSize; nPosition < nEndOffset - 1; nPosition++) { + next_offset_for_pos[nPosition - nPreviousBlockSize] = first_offset_for_byte[((unsigned int)pInWindow[nPosition]) | (((unsigned int)pInWindow[nPosition + 1]) << 8)]; + first_offset_for_byte[((unsigned int)pInWindow[nPosition]) | (((unsigned int)pInWindow[nPosition + 1]) << 8)] = nPosition; + } + + for (nPosition = nPreviousBlockSize + 1; nPosition < (nEndOffset - 1); nPosition++) { + lzsa_match* match = pCompressor->match + ((nPosition - nPreviousBlockSize) << MATCHES_PER_INDEX_SHIFT_V2); + int m = 0, nInserted = 0; + int nMatchPos; + + while (m < 15 && match[m].length) + m++; + + for (nMatchPos = next_offset_for_pos[nPosition - nPreviousBlockSize]; m < 15 && nMatchPos >= 0; nMatchPos = next_offset_for_pos[nMatchPos - nPreviousBlockSize]) { + int nMatchOffset = nPosition - nMatchPos; + int nExistingMatchIdx; + int nAlreadyExists = 0; + + for (nExistingMatchIdx = 0; nExistingMatchIdx < m; nExistingMatchIdx++) { + if (match[nExistingMatchIdx].offset == nMatchOffset) { + nAlreadyExists = 1; + break; + } + } + + if (!nAlreadyExists) { + int nMatchLen = 2; + while (nMatchLen < 16 && (nPosition + nMatchLen + 4) < nEndOffset && !memcmp(pInWindow + nMatchPos + nMatchLen, pInWindow + nPosition + nMatchLen, 4)) + nMatchLen += 4; + while (nMatchLen < 16 && (nPosition + nMatchLen) < nEndOffset && pInWindow[nMatchPos + nMatchLen] == pInWindow[nPosition + nMatchLen]) + nMatchLen++; + match[m].length = nMatchLen; + match[m].offset = nMatchOffset; + m++; + nInserted++; + if (nInserted >= 15) + break; + } + } + } + + /* Compress optimally with the extra matches */ + memset(pCompressor->best_match, 0, BLOCK_SIZE * sizeof(lzsa_match)); + lzsa_optimize_forward_v2(pCompressor, pInWindow, pCompressor->best_match - nPreviousBlockSize, nPreviousBlockSize, nPreviousBlockSize + nInDataSize, 1 /* reduce */, 0 /* use forward reps */, nArrivalsPerPosition); + + nPasses = 0; + do { + nDidReduce = lzsa_optimize_command_count_v2(pCompressor, pInWindow, pCompressor->best_match - nPreviousBlockSize, nPreviousBlockSize, nPreviousBlockSize + nInDataSize); + nPasses++; + } while (nDidReduce && nPasses < 20); + + nSupplementedCompressedSize = lzsa_get_compressed_size_v2(pCompressor, pCompressor->best_match - nPreviousBlockSize, nPreviousBlockSize, nPreviousBlockSize + nInDataSize); + if (nSupplementedCompressedSize > 0 && nSupplementedCompressedSize < nReducedCompressedSize) { + /* Pick the parse with the extra matches as it didn't negatively affect the size */ + pBestMatch = pCompressor->best_match - nPreviousBlockSize; + } + } + } + + nResult = lzsa_write_block_v2(pCompressor, pBestMatch, pInWindow, nPreviousBlockSize, nPreviousBlockSize + nInDataSize, pOutData, nMaxOutDataSize); + if (nResult < 0 && pCompressor->flags & LZSA_FLAG_RAW_BLOCK) { + nResult = lzsa_write_raw_uncompressed_block_v2(pCompressor, pInWindow, nPreviousBlockSize, nPreviousBlockSize + nInDataSize, pOutData, nMaxOutDataSize); + } + + return nResult; +} diff --git a/tools/rasm/lzsa-master/src/shrink_block_v2.h b/tools/rasm/lzsa-master/src/shrink_block_v2.h new file mode 100644 index 0000000..4a83608 --- /dev/null +++ b/tools/rasm/lzsa-master/src/shrink_block_v2.h @@ -0,0 +1,53 @@ +/* + * shrink_block_v2.h - LZSA2 block compressor definitions + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#ifndef _SHRINK_BLOCK_V2_H +#define _SHRINK_BLOCK_V2_H + +/* Forward declarations */ +typedef struct _lzsa_compressor lzsa_compressor; + +/** + * Select the most optimal matches, reduce the token count if possible, and then emit a block of compressed LZSA2 data + * + * @param pCompressor compression context + * @param pInWindow pointer to input data window (previously compressed bytes + bytes to compress) + * @param nPreviousBlockSize number of previously compressed bytes (or 0 for none) + * @param nInDataSize number of input bytes to compress + * @param pOutData pointer to output buffer + * @param nMaxOutDataSize maximum size of output buffer, in bytes + * + * @return size of compressed data in output buffer, or -1 if the data is uncompressible + */ +int lzsa_optimize_and_write_block_v2(lzsa_compressor *pCompressor, const unsigned char *pInWindow, const int nPreviousBlockSize, const int nInDataSize, unsigned char *pOutData, const int nMaxOutDataSize); + +#endif /* _SHRINK_BLOCK_V2_H */ diff --git a/tools/rasm/lzsa-master/src/shrink_context.c b/tools/rasm/lzsa-master/src/shrink_context.c new file mode 100644 index 0000000..0bb8a6d --- /dev/null +++ b/tools/rasm/lzsa-master/src/shrink_context.c @@ -0,0 +1,254 @@ +/* + * shrink_context.c - compression context implementation + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#include +#include +#include "shrink_context.h" +#include "shrink_block_v1.h" +#include "shrink_block_v2.h" +#include "format.h" +#include "matchfinder.h" +#include "lib.h" + +/** + * Initialize compression context + * + * @param pCompressor compression context to initialize + * @param nMaxWindowSize maximum size of input data window (previously compressed bytes + bytes to compress) + * @param nMinMatchSize minimum match size (cannot be less than MIN_MATCH_SIZE) + * @param nFlags compression flags + * + * @return 0 for success, non-zero for failure + */ +int lzsa_compressor_init(lzsa_compressor *pCompressor, const int nMaxWindowSize, const int nMinMatchSize, const int nFormatVersion, const int nFlags) { + int nResult; + int nMinMatchSizeForFormat = (nFormatVersion == 1) ? MIN_MATCH_SIZE_V1 : MIN_MATCH_SIZE_V2; + int nMaxMinMatchForFormat = (nFormatVersion == 1) ? 5 : 3; + + nResult = divsufsort_init(&pCompressor->divsufsort_context); + pCompressor->intervals = NULL; + pCompressor->pos_data = NULL; + pCompressor->open_intervals = NULL; + pCompressor->match = NULL; + pCompressor->best_match = NULL; + pCompressor->improved_match = NULL; + pCompressor->arrival = NULL; + pCompressor->rep_handled_mask = NULL; + pCompressor->first_offset_for_byte = NULL; + pCompressor->next_offset_for_pos = NULL; + pCompressor->min_match_size = nMinMatchSize; + if (pCompressor->min_match_size < nMinMatchSizeForFormat) + pCompressor->min_match_size = nMinMatchSizeForFormat; + else if (pCompressor->min_match_size > nMaxMinMatchForFormat) + pCompressor->min_match_size = nMaxMinMatchForFormat; + pCompressor->format_version = nFormatVersion; + pCompressor->flags = nFlags; + pCompressor->safe_dist = 0; + pCompressor->num_commands = 0; + + memset(&pCompressor->stats, 0, sizeof(pCompressor->stats)); + pCompressor->stats.min_literals = -1; + pCompressor->stats.min_match_len = -1; + pCompressor->stats.min_offset = -1; + pCompressor->stats.min_rle1_len = -1; + pCompressor->stats.min_rle2_len = -1; + + if (!nResult) { + pCompressor->intervals = (unsigned int *)malloc(nMaxWindowSize * sizeof(unsigned int)); + + if (pCompressor->intervals) { + pCompressor->pos_data = (unsigned int *)malloc(nMaxWindowSize * sizeof(unsigned int)); + + if (pCompressor->pos_data) { + pCompressor->open_intervals = (unsigned int *)malloc((LCP_AND_TAG_MAX + 1) * sizeof(unsigned int)); + + if (pCompressor->open_intervals) { + pCompressor->arrival = (lzsa_arrival *)malloc(((BLOCK_SIZE + 1) << ARRIVALS_PER_POSITION_SHIFT) * sizeof(lzsa_arrival)); + + if (pCompressor->arrival) { + pCompressor->best_match = (lzsa_match *)malloc(BLOCK_SIZE * sizeof(lzsa_match)); + + if (pCompressor->best_match) { + pCompressor->improved_match = (lzsa_match *)malloc(BLOCK_SIZE * sizeof(lzsa_match)); + + if (pCompressor->improved_match) { + if (pCompressor->format_version == 2) + pCompressor->match = (lzsa_match *)malloc(BLOCK_SIZE * NMATCHES_PER_INDEX_V2 * sizeof(lzsa_match)); + else + pCompressor->match = (lzsa_match *)malloc(BLOCK_SIZE * NMATCHES_PER_INDEX_V1 * sizeof(lzsa_match)); + if (pCompressor->match) { + if (pCompressor->format_version == 2) { + pCompressor->rep_handled_mask = (char*)malloc(NARRIVALS_PER_POSITION_V2_BIG * ((LCP_MAX + 1) / 8) * sizeof(char)); + if (pCompressor->rep_handled_mask) { + pCompressor->first_offset_for_byte = (int*)malloc(65536 * sizeof(int)); + if (pCompressor->first_offset_for_byte) { + pCompressor->next_offset_for_pos = (int*)malloc(BLOCK_SIZE * sizeof(int)); + if (pCompressor->next_offset_for_pos) { + return 0; + } + } + } + } + else { + return 0; + } + } + } + } + } + } + } + } + } + + lzsa_compressor_destroy(pCompressor); + return 100; +} + +/** + * Clean up compression context and free up any associated resources + * + * @param pCompressor compression context to clean up + */ +void lzsa_compressor_destroy(lzsa_compressor *pCompressor) { + divsufsort_destroy(&pCompressor->divsufsort_context); + + if (pCompressor->next_offset_for_pos) { + free(pCompressor->next_offset_for_pos); + pCompressor->next_offset_for_pos = NULL; + } + + if (pCompressor->first_offset_for_byte) { + free(pCompressor->first_offset_for_byte); + pCompressor->first_offset_for_byte = NULL; + } + + if (pCompressor->rep_handled_mask) { + free(pCompressor->rep_handled_mask); + pCompressor->rep_handled_mask = NULL; + } + + if (pCompressor->match) { + free(pCompressor->match); + pCompressor->match = NULL; + } + + if (pCompressor->improved_match) { + free(pCompressor->improved_match); + pCompressor->improved_match = NULL; + } + + if (pCompressor->arrival) { + free(pCompressor->arrival); + pCompressor->arrival = NULL; + } + + if (pCompressor->best_match) { + free(pCompressor->best_match); + pCompressor->best_match = NULL; + } + + if (pCompressor->open_intervals) { + free(pCompressor->open_intervals); + pCompressor->open_intervals = NULL; + } + + if (pCompressor->pos_data) { + free(pCompressor->pos_data); + pCompressor->pos_data = NULL; + } + + if (pCompressor->intervals) { + free(pCompressor->intervals); + pCompressor->intervals = NULL; + } +} + +/** + * Compress one block of data + * + * @param pCompressor compression context + * @param pInWindow pointer to input data window (previously compressed bytes + bytes to compress) + * @param nPreviousBlockSize number of previously compressed bytes (or 0 for none) + * @param nInDataSize number of input bytes to compress + * @param pOutData pointer to output buffer + * @param nMaxOutDataSize maximum size of output buffer, in bytes + * + * @return size of compressed data in output buffer, or -1 if the data is uncompressible + */ +int lzsa_compressor_shrink_block(lzsa_compressor *pCompressor, unsigned char *pInWindow, const int nPreviousBlockSize, const int nInDataSize, unsigned char *pOutData, const int nMaxOutDataSize) { + int nCompressedSize; + + if (pCompressor->flags & LZSA_FLAG_RAW_BACKWARD) { + lzsa_reverse_buffer(pInWindow + nPreviousBlockSize, nInDataSize); + } + + if (lzsa_build_suffix_array(pCompressor, pInWindow, nPreviousBlockSize + nInDataSize)) + nCompressedSize = -1; + else { + if (nPreviousBlockSize) { + lzsa_skip_matches(pCompressor, 0, nPreviousBlockSize); + } + lzsa_find_all_matches(pCompressor, (pCompressor->format_version == 2) ? NMATCHES_PER_INDEX_V2 : NMATCHES_PER_INDEX_V1, nPreviousBlockSize, nPreviousBlockSize + nInDataSize); + + if (pCompressor->format_version == 1) { + nCompressedSize = lzsa_optimize_and_write_block_v1(pCompressor, pInWindow, nPreviousBlockSize, nInDataSize, pOutData, nMaxOutDataSize); + if (nCompressedSize != -1 && (pCompressor->flags & LZSA_FLAG_RAW_BACKWARD)) { + lzsa_reverse_buffer(pOutData, nCompressedSize); + } + } + else if (pCompressor->format_version == 2) { + nCompressedSize = lzsa_optimize_and_write_block_v2(pCompressor, pInWindow, nPreviousBlockSize, nInDataSize, pOutData, nMaxOutDataSize); + if (nCompressedSize != -1 && (pCompressor->flags & LZSA_FLAG_RAW_BACKWARD)) { + lzsa_reverse_buffer(pOutData, nCompressedSize); + } + } + else { + nCompressedSize = -1; + } + } + + if (pCompressor->flags & LZSA_FLAG_RAW_BACKWARD) { + lzsa_reverse_buffer(pInWindow + nPreviousBlockSize, nInDataSize); + } + + return nCompressedSize; +} + +/** + * Get the number of compression commands issued in compressed data blocks + * + * @return number of commands + */ +int lzsa_compressor_get_command_count(lzsa_compressor *pCompressor) { + return pCompressor->num_commands; +} diff --git a/tools/rasm/lzsa-master/src/shrink_context.h b/tools/rasm/lzsa-master/src/shrink_context.h new file mode 100644 index 0000000..54e4671 --- /dev/null +++ b/tools/rasm/lzsa-master/src/shrink_context.h @@ -0,0 +1,182 @@ +/* + * shrink_context.h - compression context definitions + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#ifndef _SHRINK_CONTEXT_H +#define _SHRINK_CONTEXT_H + +#include "divsufsort.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define LCP_BITS 14 +#define TAG_BITS 4 +#define LCP_MAX ((1U<<(LCP_BITS - TAG_BITS)) - 1) +#define LCP_AND_TAG_MAX (1U<<(LCP_BITS - 1)) +#define LCP_SHIFT (31-LCP_BITS) +#define LCP_MASK (((1U< + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#include +#include +#include "shrink_inmem.h" +#include "shrink_context.h" +#include "frame.h" +#include "format.h" +#include "lib.h" + +/** + * Get maximum compressed size of input(source) data + * + * @param nInputSize input(source) size in bytes + * + * @return maximum compressed size + */ +size_t lzsa_get_max_compressed_size_inmem(size_t nInputSize) { + return lzsa_get_header_size() + ((nInputSize + (BLOCK_SIZE - 1)) >> 16) * lzsa_get_frame_size() + nInputSize + lzsa_get_frame_size() /* footer */; +} + +/** + * Compress memory + * + * @param pInputData pointer to input(source) data to compress + * @param pOutBuffer buffer for compressed data + * @param nInputSize input(source) size in bytes + * @param nMaxOutBufferSize maximum capacity of compression buffer + * @param nFlags compression flags (LZSA_FLAG_xxx) + * @param nMinMatchSize minimum match size + * @param nFormatVersion version of format to use (1-2) + * + * @return actual compressed size, or -1 for error + */ +size_t lzsa_compress_inmem(unsigned char *pInputData, unsigned char *pOutBuffer, size_t nInputSize, size_t nMaxOutBufferSize, + const unsigned int nFlags, const int nMinMatchSize, const int nFormatVersion) { + lzsa_compressor compressor; + size_t nOriginalSize = 0; + size_t nCompressedSize = 0L; + int nResult; + int nError = 0; + + nResult = lzsa_compressor_init(&compressor, BLOCK_SIZE * 2, nMinMatchSize, nFormatVersion, nFlags); + if (nResult != 0) { + return -1; + } + + if ((nFlags & LZSA_FLAG_RAW_BLOCK) == 0) { + int nHeaderSize = lzsa_encode_header(pOutBuffer, (int)nMaxOutBufferSize, nFormatVersion); + if (nHeaderSize < 0) + nError = LZSA_ERROR_COMPRESSION; + else { + nCompressedSize += nHeaderSize; + } + } + + int nPreviousBlockSize = 0; + int nNumBlocks = 0; + + while (nOriginalSize < nInputSize && !nError) { + int nInDataSize; + + nInDataSize = (int)(nInputSize - nOriginalSize); + if (nInDataSize > BLOCK_SIZE) + nInDataSize = BLOCK_SIZE; + + if (nInDataSize > 0) { + if ((nFlags & LZSA_FLAG_RAW_BLOCK) != 0 && nNumBlocks) { + nError = LZSA_ERROR_RAW_TOOLARGE; + break; + } + + int nOutDataSize; + int nOutDataEnd = (int)(nMaxOutBufferSize - (lzsa_get_frame_size() + nCompressedSize + lzsa_get_frame_size() /* footer */)); + int nFrameSize = lzsa_get_frame_size(); + + if ((nFlags & LZSA_FLAG_RAW_BLOCK) != 0) { + nFrameSize = 0; + nOutDataEnd = (int)(nMaxOutBufferSize - nCompressedSize); + } + + if (nOutDataEnd > BLOCK_SIZE) + nOutDataEnd = BLOCK_SIZE; + + nOutDataSize = lzsa_compressor_shrink_block(&compressor, pInputData + nOriginalSize - nPreviousBlockSize, nPreviousBlockSize, nInDataSize, pOutBuffer + nFrameSize + nCompressedSize, nOutDataEnd); + if (nOutDataSize >= 0) { + /* Write compressed block */ + + if ((nFlags & LZSA_FLAG_RAW_BLOCK) == 0) { + int nBlockheaderSize = lzsa_encode_compressed_block_frame(pOutBuffer + nCompressedSize, (int)(nMaxOutBufferSize - nCompressedSize), nOutDataSize); + if (nBlockheaderSize < 0) + nError = LZSA_ERROR_COMPRESSION; + else { + nCompressedSize += nBlockheaderSize; + } + } + + if (!nError) { + nOriginalSize += nInDataSize; + nCompressedSize += nOutDataSize; + } + } + else { + /* Write uncompressible, literal block */ + + if ((nFlags & LZSA_FLAG_RAW_BLOCK) != 0) { + nError = LZSA_ERROR_RAW_UNCOMPRESSED; + break; + } + + int nBlockheaderSize = lzsa_encode_uncompressed_block_frame(pOutBuffer + nCompressedSize, (int)(nMaxOutBufferSize - nCompressedSize), nInDataSize); + if (nBlockheaderSize < 0) + nError = LZSA_ERROR_COMPRESSION; + else { + if ((size_t)nInDataSize > (nMaxOutBufferSize - (nCompressedSize + nBlockheaderSize))) + nError = LZSA_ERROR_DST; + else { + memcpy(pOutBuffer + nBlockheaderSize + nCompressedSize, pInputData + nOriginalSize, nInDataSize); + + nOriginalSize += nInDataSize; + nCompressedSize += nBlockheaderSize + nInDataSize; + } + } + } + + nPreviousBlockSize = nInDataSize; + nNumBlocks++; + } + } + + if (!nError) { + int nFooterSize; + + if ((nFlags & LZSA_FLAG_RAW_BLOCK) != 0) { + nFooterSize = 0; + } + else { + nFooterSize = lzsa_encode_footer_frame(pOutBuffer + nCompressedSize, (int)(nMaxOutBufferSize - nCompressedSize)); + if (nFooterSize < 0) + nError = LZSA_ERROR_COMPRESSION; + } + + nCompressedSize += nFooterSize; + } + + lzsa_compressor_destroy(&compressor); + + if (nError) { + return -1; + } + else { + return nCompressedSize; + } +} + diff --git a/tools/rasm/lzsa-master/src/shrink_inmem.h b/tools/rasm/lzsa-master/src/shrink_inmem.h new file mode 100644 index 0000000..2bd8f27 --- /dev/null +++ b/tools/rasm/lzsa-master/src/shrink_inmem.h @@ -0,0 +1,71 @@ +/* + * shrink_inmem.h - in-memory compression definitions + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#ifndef _SHRINK_INMEM_H +#define _SHRINK_INMEM_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Get maximum compressed size of input(source) data + * + * @param nInputSize input(source) size in bytes + * + * @return maximum compressed size + */ +size_t lzsa_get_max_compressed_size_inmem(size_t nInputSize); + +/** + * Compress memory + * + * @param pInputData pointer to input(source) data to compress + * @param pOutBuffer buffer for compressed data + * @param nInputSize input(source) size in bytes + * @param nMaxOutBufferSize maximum capacity of compression buffer + * @param nFlags compression flags (LZSA_FLAG_xxx) + * @param nMinMatchSize minimum match size + * @param nFormatVersion version of format to use (1-2) + * + * @return actual compressed size, or -1 for error + */ +size_t lzsa_compress_inmem(unsigned char *pInputData, unsigned char *pOutBuffer, size_t nInputSize, size_t nMaxOutBufferSize, + const unsigned int nFlags, const int nMinMatchSize, const int nFormatVersion); + +#ifdef __cplusplus +} +#endif + +#endif /* _SHRINK_INMEM_H */ diff --git a/tools/rasm/lzsa-master/src/shrink_streaming.c b/tools/rasm/lzsa-master/src/shrink_streaming.c new file mode 100644 index 0000000..2e1cf12 --- /dev/null +++ b/tools/rasm/lzsa-master/src/shrink_streaming.c @@ -0,0 +1,320 @@ +/* + * shrink_streaming.c - streaming compression implementation + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#include +#include +#include "shrink_streaming.h" +#include "format.h" +#include "frame.h" +#include "lib.h" +#ifdef _WIN32 +#include +#else +#include +#endif + +/** + * Delete file + * + * @param pszInFilename name of file to delete + */ +static void lzsa_delete_file(const char *pszInFilename) { +#ifdef _WIN32 + DeleteFileA(pszInFilename); +#else + remove(pszInFilename); +#endif +} + +/*-------------- File API -------------- */ + +/** + * Compress file + * + * @param pszInFilename name of input(source) file to compress + * @param pszOutFilename name of output(compressed) file to generate + * @param pszDictionaryFilename name of dictionary file, or NULL for none + * @param nFlags compression flags (LZSA_FLAG_xxx) + * @param nMinMatchSize minimum match size + * @param nFormatVersion version of format to use (1-2) + * @param progress progress function, called after compressing each block, or NULL for none + * @param pOriginalSize pointer to returned input(source) size, updated when this function is successful + * @param pCompressedSize pointer to returned output(compressed) size, updated when this function is successful + * @param pCommandCount pointer to returned token(compression commands) count, updated when this function is successful + * @param pSafeDist pointer to return safe distance for raw blocks, updated when this function is successful + * @param pStats pointer to compression stats that are filled if this function is successful, or NULL + * + * @return LZSA_OK for success, or an error value from lzsa_status_t + */ +lzsa_status_t lzsa_compress_file(const char *pszInFilename, const char *pszOutFilename, const char *pszDictionaryFilename, const unsigned int nFlags, const int nMinMatchSize, const int nFormatVersion, + void(*progress)(long long nOriginalSize, long long nCompressedSize), long long *pOriginalSize, long long *pCompressedSize, int *pCommandCount, int *pSafeDist, lzsa_stats *pStats) { + lzsa_stream_t inStream, outStream; + void *pDictionaryData = NULL; + int nDictionaryDataSize = 0; + lzsa_status_t nStatus; + + if (lzsa_filestream_open(&inStream, pszInFilename, "rb") < 0) { + return LZSA_ERROR_SRC; + } + + if (lzsa_filestream_open(&outStream, pszOutFilename, "wb") < 0) { + inStream.close(&inStream); + return LZSA_ERROR_DST; + } + + nStatus = lzsa_dictionary_load(pszDictionaryFilename, &pDictionaryData, &nDictionaryDataSize); + + if (nStatus) { + outStream.close(&outStream); + inStream.close(&inStream); + lzsa_delete_file(pszOutFilename); + return nStatus; + } + + nStatus = lzsa_compress_stream(&inStream, &outStream, pDictionaryData, nDictionaryDataSize, nFlags, nMinMatchSize, nFormatVersion, progress, pOriginalSize, pCompressedSize, pCommandCount, pSafeDist, pStats); + + lzsa_dictionary_free(&pDictionaryData); + outStream.close(&outStream); + inStream.close(&inStream); + + if (nStatus) { + lzsa_delete_file(pszOutFilename); + } + + return nStatus; +} + +/*-------------- Streaming API -------------- */ + +/** + * Compress stream + * + * @param pInStream input(source) stream to compress + * @param pOutStream output(compressed) stream to write to + * @param pDictionaryData dictionary contents, or NULL for none + * @param nDictionaryDataSize size of dictionary contents, or 0 + * @param nFlags compression flags (LZSA_FLAG_xxx) + * @param nMinMatchSize minimum match size + * @param nFormatVersion version of format to use (1-2) + * @param progress progress function, called after compressing each block, or NULL for none + * @param pOriginalSize pointer to returned input(source) size, updated when this function is successful + * @param pCompressedSize pointer to returned output(compressed) size, updated when this function is successful + * @param pCommandCount pointer to returned token(compression commands) count, updated when this function is successful + * @param pSafeDist pointer to return safe distance for raw blocks, updated when this function is successful + * @param pStats pointer to compression stats that are filled if this function is successful, or NULL + * + * @return LZSA_OK for success, or an error value from lzsa_status_t + */ +lzsa_status_t lzsa_compress_stream(lzsa_stream_t *pInStream, lzsa_stream_t *pOutStream, const void *pDictionaryData, int nDictionaryDataSize, + const unsigned int nFlags, const int nMinMatchSize, const int nFormatVersion, + void(*progress)(long long nOriginalSize, long long nCompressedSize), long long *pOriginalSize, long long *pCompressedSize, int *pCommandCount, int *pSafeDist, lzsa_stats *pStats) { + unsigned char *pInData, *pOutData; + lzsa_compressor compressor; + long long nOriginalSize = 0LL, nCompressedSize = 0LL; + int nResult; + unsigned char cFrameData[16]; + int nError = 0; + int nRawPadding = (nFlags & LZSA_FLAG_RAW_BLOCK) ? 8 : 0; + + pInData = (unsigned char*)malloc(BLOCK_SIZE * 2); + if (!pInData) { + return LZSA_ERROR_MEMORY; + } + memset(pInData, 0, BLOCK_SIZE * 2); + + pOutData = (unsigned char*)malloc(BLOCK_SIZE); + if (!pOutData) { + free(pInData); + pInData = NULL; + + return LZSA_ERROR_MEMORY; + } + memset(pOutData, 0, BLOCK_SIZE); + + nResult = lzsa_compressor_init(&compressor, BLOCK_SIZE * 2, nMinMatchSize, nFormatVersion, nFlags); + if (nResult != 0) { + free(pOutData); + pOutData = NULL; + + free(pInData); + pInData = NULL; + + return LZSA_ERROR_MEMORY; + } + + if ((nFlags & LZSA_FLAG_RAW_BLOCK) == 0) { + int nHeaderSize = lzsa_encode_header(cFrameData, 16, nFormatVersion); + if (nHeaderSize < 0) + nError = LZSA_ERROR_COMPRESSION; + else { + if (pOutStream->write(pOutStream, cFrameData, nHeaderSize) != nHeaderSize) + nError = LZSA_ERROR_DST; + nCompressedSize += (long long)nHeaderSize; + } + } + + int nPreviousBlockSize = 0; + int nNumBlocks = 0; + + while (!pInStream->eof(pInStream) && !nError) { + int nInDataSize; + + if (nPreviousBlockSize) { + memcpy(pInData + BLOCK_SIZE - nPreviousBlockSize, pInData + BLOCK_SIZE, nPreviousBlockSize); + } + else if (nDictionaryDataSize && pDictionaryData) { + nPreviousBlockSize = nDictionaryDataSize; + memcpy(pInData + BLOCK_SIZE - nPreviousBlockSize, pDictionaryData, nPreviousBlockSize); + } + + nInDataSize = (int)pInStream->read(pInStream, pInData + BLOCK_SIZE, BLOCK_SIZE); + if (nInDataSize > 0) { + if ((nFlags & LZSA_FLAG_RAW_BLOCK) != 0 && nNumBlocks) { + nError = LZSA_ERROR_RAW_TOOLARGE; + break; + } + nDictionaryDataSize = 0; + + int nOutDataSize; + + nOutDataSize = lzsa_compressor_shrink_block(&compressor, pInData + BLOCK_SIZE - nPreviousBlockSize, nPreviousBlockSize, nInDataSize, pOutData, ((nInDataSize + nRawPadding) >= BLOCK_SIZE) ? BLOCK_SIZE : (nInDataSize + nRawPadding)); + if (nOutDataSize >= 0) { + /* Write compressed block */ + + if ((nFlags & LZSA_FLAG_RAW_BLOCK) == 0) { + int nBlockheaderSize = lzsa_encode_compressed_block_frame(cFrameData, 16, nOutDataSize); + if (nBlockheaderSize < 0) + nError = LZSA_ERROR_COMPRESSION; + else { + nCompressedSize += (long long)nBlockheaderSize; + if (pOutStream->write(pOutStream, cFrameData, nBlockheaderSize) != (size_t)nBlockheaderSize) { + nError = LZSA_ERROR_DST; + } + } + } + + if (!nError) { + if (pOutStream->write(pOutStream, pOutData, (size_t)nOutDataSize) != (size_t)nOutDataSize) { + nError = LZSA_ERROR_DST; + } + else { + nOriginalSize += (long long)nInDataSize; + nCompressedSize += (long long)nOutDataSize; + } + } + } + else { + /* Write uncompressible, literal block */ + + if ((nFlags & LZSA_FLAG_RAW_BLOCK) != 0) { + nError = LZSA_ERROR_RAW_UNCOMPRESSED; + break; + } + + int nBlockheaderSize = lzsa_encode_uncompressed_block_frame(cFrameData, 16, nInDataSize); + if (nBlockheaderSize < 0) + nError = LZSA_ERROR_COMPRESSION; + else { + if (pOutStream->write(pOutStream, cFrameData, nBlockheaderSize) != (size_t)nBlockheaderSize) { + nError = LZSA_ERROR_DST; + } + else { + if (pOutStream->write(pOutStream, pInData + BLOCK_SIZE, (size_t)nInDataSize) != (size_t)nInDataSize) { + nError = LZSA_ERROR_DST; + } + else { + nOriginalSize += (long long)nInDataSize; + nCompressedSize += (long long)nBlockheaderSize + (long long)nInDataSize; + } + } + } + } + + nPreviousBlockSize = nInDataSize; + nNumBlocks++; + } + + if (!nError && !pInStream->eof(pInStream)) { + if (progress) + progress(nOriginalSize, nCompressedSize); + } + } + + if (!nError) { + int nFooterSize; + + if ((nFlags & LZSA_FLAG_RAW_BLOCK) != 0) { + nFooterSize = 0; + } + else { + nFooterSize = lzsa_encode_footer_frame(cFrameData, 16); + if (nFooterSize < 0) + nError = LZSA_ERROR_COMPRESSION; + } + + if (pOutStream->write(pOutStream, cFrameData, nFooterSize) != nFooterSize) + nError = LZSA_ERROR_DST; + nCompressedSize += (long long)nFooterSize; + } + + if (progress) + progress(nOriginalSize, nCompressedSize); + + int nCommandCount = lzsa_compressor_get_command_count(&compressor); + int nSafeDist = compressor.safe_dist; + + if (pStats) + *pStats = compressor.stats; + + lzsa_compressor_destroy(&compressor); + + free(pOutData); + pOutData = NULL; + + free(pInData); + pInData = NULL; + + if (nError) { + return nError; + } + else { + if (pOriginalSize) + *pOriginalSize = nOriginalSize; + if (pCompressedSize) + *pCompressedSize = nCompressedSize; + if (pCommandCount) + *pCommandCount = nCommandCount; + if (pSafeDist) + *pSafeDist = nSafeDist; + return LZSA_OK; + } +} diff --git a/tools/rasm/lzsa-master/src/shrink_streaming.h b/tools/rasm/lzsa-master/src/shrink_streaming.h new file mode 100644 index 0000000..0920edf --- /dev/null +++ b/tools/rasm/lzsa-master/src/shrink_streaming.h @@ -0,0 +1,99 @@ +/* + * shrink_streaming.h - streaming compression definitions + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#ifndef _SHRINK_STREAMING_H +#define _SHRINK_STREAMING_H + +#include "stream.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declaration */ +typedef enum _lzsa_status_t lzsa_status_t; +typedef struct _lzsa_stats lzsa_stats; + +/*-------------- File API -------------- */ + +/** + * Compress file + * + * @param pszInFilename name of input(source) file to compress + * @param pszOutFilename name of output(compressed) file to generate + * @param pszDictionaryFilename name of dictionary file, or NULL for none + * @param nFlags compression flags (LZSA_FLAG_xxx) + * @param nMinMatchSize minimum match size + * @param nFormatVersion version of format to use (1-2) + * @param progress progress function, called after compressing each block, or NULL for none + * @param pOriginalSize pointer to returned input(source) size, updated when this function is successful + * @param pCompressedSize pointer to returned output(compressed) size, updated when this function is successful + * @param pCommandCount pointer to returned token(compression commands) count, updated when this function is successful + * @param pSafeDist pointer to return safe distance for raw blocks, updated when this function is successful + * @param pStats pointer to compression stats that are filled if this function is successful, or NULL + * + * @return LZSA_OK for success, or an error value from lzsa_status_t + */ +lzsa_status_t lzsa_compress_file(const char *pszInFilename, const char *pszOutFilename, const char *pszDictionaryFilename, + const unsigned int nFlags, const int nMinMatchSize, const int nFormatVersion, + void(*progress)(long long nOriginalSize, long long nCompressedSize), long long *pOriginalSize, long long *pCompressedSize, int *pCommandCount, int *pSafeDist, lzsa_stats *pStats); + +/*-------------- Streaming API -------------- */ + +/** + * Compress stream + * + * @param pInStream input(source) stream to compress + * @param pOutStream output(compressed) stream to write to + * @param pDictionaryData dictionary contents, or NULL for none + * @param nDictionaryDataSize size of dictionary contents, or 0 + * @param nFlags compression flags (LZSA_FLAG_xxx) + * @param nMinMatchSize minimum match size + * @param nFormatVersion version of format to use (1-2) + * @param progress progress function, called after compressing each block, or NULL for none + * @param pOriginalSize pointer to returned input(source) size, updated when this function is successful + * @param pCompressedSize pointer to returned output(compressed) size, updated when this function is successful + * @param pCommandCount pointer to returned token(compression commands) count, updated when this function is successful + * @param pSafeDist pointer to return safe distance for raw blocks, updated when this function is successful + * @param pStats pointer to compression stats that are filled if this function is successful, or NULL + * + * @return LZSA_OK for success, or an error value from lzsa_status_t + */ +lzsa_status_t lzsa_compress_stream(lzsa_stream_t *pInStream, lzsa_stream_t *pOutStream, const void *pDictionaryData, int nDictionaryDataSize, + const unsigned int nFlags, const int nMinMatchSize, const int nFormatVersion, + void(*progress)(long long nOriginalSize, long long nCompressedSize), long long *pOriginalSize, long long *pCompressedSize, int *pCommandCount, int *pSafeDist, lzsa_stats *pStats); + +#ifdef __cplusplus +} +#endif + +#endif /* _SHRINK_STREAMING_H */ diff --git a/tools/rasm/lzsa-master/src/stream.c b/tools/rasm/lzsa-master/src/stream.c new file mode 100644 index 0000000..8937487 --- /dev/null +++ b/tools/rasm/lzsa-master/src/stream.c @@ -0,0 +1,111 @@ +/* + * stream.c - streaming I/O implementation + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#include +#include +#include +#include "stream.h" + +/** + * Close file stream + * + * @param stream stream + */ +static void lzsa_filestream_close(lzsa_stream_t *stream) { + if (stream->obj) { + fclose((FILE*)stream->obj); + stream->obj = NULL; + stream->read = NULL; + stream->write = NULL; + stream->eof = NULL; + stream->close = NULL; + } +} + +/** + * Read from file stream + * + * @param stream stream + * @param ptr buffer to read into + * @param size number of bytes to read + * + * @return number of bytes read + */ +static size_t lzsa_filestream_read(lzsa_stream_t *stream, void *ptr, size_t size) { + return fread(ptr, 1, size, (FILE*)stream->obj); +} + +/** + * Write to file stream + * + * @param stream stream + * @param ptr buffer to write from + * @param size number of bytes to write + * + * @return number of bytes written + */ +static size_t lzsa_filestream_write(lzsa_stream_t *stream, void *ptr, size_t size) { + return fwrite(ptr, 1, size, (FILE*)stream->obj); +} + +/** + * Check if file stream has reached the end of the data + * + * @param stream stream + * + * @return nonzero if the end of the data has been reached, 0 if there is more data + */ +static int lzsa_filestream_eof(lzsa_stream_t *stream) { + return feof((FILE*)stream->obj); +} + +/** + * Open file and create an I/O stream from it + * + * @param stream stream to fill out + * @param pszInFilename filename + * @param pszMode open mode, as with fopen() + * + * @return 0 for success, nonzero for failure + */ +int lzsa_filestream_open(lzsa_stream_t *stream, const char *pszInFilename, const char *pszMode) { + stream->obj = (void*)fopen(pszInFilename, pszMode); + if (stream->obj) { + stream->read = lzsa_filestream_read; + stream->write = lzsa_filestream_write; + stream->eof = lzsa_filestream_eof; + stream->close = lzsa_filestream_close; + return 0; + } + else + return -1; +} diff --git a/tools/rasm/lzsa-master/src/stream.h b/tools/rasm/lzsa-master/src/stream.h new file mode 100644 index 0000000..a8b7922 --- /dev/null +++ b/tools/rasm/lzsa-master/src/stream.h @@ -0,0 +1,103 @@ +/* + * stream.h - streaming I/O definitions + * + * Copyright (C) 2019 Emmanuel Marty + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori + * + * Inspired by LZ4 by Yann Collet. https://github.com/lz4/lz4 + * With help, ideas, optimizations and speed measurements by spke + * With ideas from Lizard by Przemyslaw Skibinski and Yann Collet. https://github.com/inikep/lizard + * Also with ideas from smallz4 by Stephan Brumme. https://create.stephan-brumme.com/smallz4/ + * + */ + +#ifndef _STREAM_H +#define _STREAM_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declaration */ +typedef struct _lzsa_stream_t lzsa_stream_t; + +/* I/O stream */ +typedef struct _lzsa_stream_t { + /** Opaque stream-specific pointer */ + void *obj; + + /** + * Read from stream + * + * @param stream stream + * @param ptr buffer to read into + * @param size number of bytes to read + * + * @return number of bytes read + */ + size_t(*read)(lzsa_stream_t *stream, void *ptr, size_t size); + + /** + * Write to stream + * + * @param stream stream + * @param ptr buffer to write from + * @param size number of bytes to write + * + * @return number of bytes written + */ + size_t(*write)(lzsa_stream_t *stream, void *ptr, size_t size); + + + /** + * Check if stream has reached the end of the data + * + * @param stream stream + * + * @return nonzero if the end of the data has been reached, 0 if there is more data + */ + int(*eof)(lzsa_stream_t *stream); + + /** + * Close stream + * + * @param stream stream + */ + void(*close)(lzsa_stream_t *stream); +} lzsa_stream_t; + +/** + * Open file and create an I/O stream from it + * + * @param stream stream to fill out + * @param pszInFilename filename + * @param pszMode open mode, as with fopen() + * + * @return 0 for success, nonzero for failure + */ +int lzsa_filestream_open(lzsa_stream_t *stream, const char *pszInFilename, const char *pszMode); + +#ifdef __cplusplus +} +#endif + +#endif /* _STREAM_H */ diff --git a/tools/rasm/makefile.MacOS b/tools/rasm/makefile.MacOS new file mode 100644 index 0000000..cbd5787 --- /dev/null +++ b/tools/rasm/makefile.MacOS @@ -0,0 +1,101 @@ +CC=gcc +EXEC=rasm + +CFLAGS=-lm -mcpu=native -o $(EXEC) -w +CFLAGS_OPT = $(CFLAGS) -O2 +CFLAGS_DBG = $(CFLAGS) -g -pthread -DRDD + +SRC_APUDIR=./apultra-master/src +SRC_LZSADIR=./lzsa-master/src +SRC_ZX0DIR=./ZX0-main/src + +APU_FLAGS=-c -O3 -fomit-frame-pointer -I$(SRC_LZSADIR)/libdivsufsort/include -I$(SRC_APUDIR) + +APU_OBJ =$(SRC_APUDIR)/expand.o +APU_OBJ+=$(SRC_APUDIR)/matchfinder.o +APU_OBJ+=$(SRC_APUDIR)/shrink.o +APU_OBJ+=$(SRC_APUDIR)/libdivsufsort/lib/divsufsort.o +APU_OBJ+=$(SRC_APUDIR)/libdivsufsort/lib/divsufsort_utils.o +APU_OBJ+=$(SRC_APUDIR)/libdivsufsort/lib/sssort.o +APU_OBJ+=$(SRC_APUDIR)/libdivsufsort/lib/trsort.o + +LZSA_FLAGS=-c -O3 -fomit-frame-pointer -I$(SRC_LZSADIR)/libdivsufsort/include -I$(SRC_LZSADIR) + +LZSA_OBJ =$(SRC_LZSADIR)/dictionary.o +LZSA_OBJ+=$(SRC_LZSADIR)/expand_block_v1.o +LZSA_OBJ+=$(SRC_LZSADIR)/expand_block_v2.o +LZSA_OBJ+=$(SRC_LZSADIR)/expand_context.o +LZSA_OBJ+=$(SRC_LZSADIR)/expand_inmem.o +LZSA_OBJ+=$(SRC_LZSADIR)/frame.o +LZSA_OBJ+=$(SRC_LZSADIR)/matchfinder.o +LZSA_OBJ+=$(SRC_LZSADIR)/shrink_block_v1.o +LZSA_OBJ+=$(SRC_LZSADIR)/shrink_block_v2.o +LZSA_OBJ+=$(SRC_LZSADIR)/shrink_context.o +LZSA_OBJ+=$(SRC_LZSADIR)/shrink_inmem.o +LZSA_OBJ+=$(SRC_LZSADIR)/stream.o + +ZX0_FLAGS=-c -O2 -I$(SRC_ZX0DIR) +ZX0_OBJ =$(SRC_ZX0DIR)/optimize.o +ZX0_OBJ+=$(SRC_ZX0DIR)/compress.o +ZX0_OBJ+=$(SRC_ZX0DIR)/memory.o + +.PHONY: prod debug install clean + +default: prod + +debug: + $(CC) $(SRC_ZX0DIR)/optimize.c $(ZX0_FLAGS) -o $(SRC_ZX0DIR)/optimize.o + $(CC) $(SRC_ZX0DIR)/compress.c $(ZX0_FLAGS) -o $(SRC_ZX0DIR)/compress.o + $(CC) $(SRC_ZX0DIR)/memory.c $(ZX0_FLAGS) -o $(SRC_ZX0DIR)/memory.o + $(CC) $(SRC_APUDIR)/expand.c $(APU_FLAGS) -o $(SRC_APUDIR)/expand.o + $(CC) $(SRC_APUDIR)/matchfinder.c $(APU_FLAGS) -o $(SRC_APUDIR)/matchfinder.o + $(CC) $(SRC_APUDIR)/shrink.c $(APU_FLAGS) -o $(SRC_APUDIR)/shrink.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/divsufsort.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/divsufsort.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/divsufsort_utils.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/divsufsort_utils.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/sssort.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/sssort.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/trsort.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/trsort.o + $(CC) $(SRC_LZSADIR)/matchfinder.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/matchfinder.o + $(CC) $(SRC_LZSADIR)/dictionary.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/dictionary.o + $(CC) $(SRC_LZSADIR)/expand_block_v1.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_block_v1.o + $(CC) $(SRC_LZSADIR)/expand_block_v2.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_block_v2.o + $(CC) $(SRC_LZSADIR)/expand_context.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_context.o + $(CC) $(SRC_LZSADIR)/expand_inmem.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_inmem.o + $(CC) $(SRC_LZSADIR)/frame.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/frame.o + $(CC) $(SRC_LZSADIR)/shrink_block_v1.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_block_v1.o + $(CC) $(SRC_LZSADIR)/shrink_block_v2.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_block_v2.o + $(CC) $(SRC_LZSADIR)/shrink_context.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_context.o + $(CC) $(SRC_LZSADIR)/shrink_inmem.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_inmem.o + $(CC) $(SRC_LZSADIR)/stream.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/stream.o + $(CC) rasm.c $(CFLAGS_DBG) + +prod: + $(CC) $(SRC_ZX0DIR)/optimize.c $(ZX0_FLAGS) -o $(SRC_ZX0DIR)/optimize.o + $(CC) $(SRC_ZX0DIR)/compress.c $(ZX0_FLAGS) -o $(SRC_ZX0DIR)/compress.o + $(CC) $(SRC_ZX0DIR)/memory.c $(ZX0_FLAGS) -o $(SRC_ZX0DIR)/memory.o + $(CC) $(SRC_APUDIR)/expand.c $(APU_FLAGS) -o $(SRC_APUDIR)/expand.o + $(CC) $(SRC_APUDIR)/matchfinder.c $(APU_FLAGS) -o $(SRC_APUDIR)/matchfinder.o + $(CC) $(SRC_APUDIR)/shrink.c $(APU_FLAGS) -o $(SRC_APUDIR)/shrink.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/divsufsort.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/divsufsort.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/divsufsort_utils.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/divsufsort_utils.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/sssort.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/sssort.o + $(CC) $(SRC_LZSADIR)/libdivsufsort/lib/trsort.c $(APU_FLAGS) -o $(SRC_APUDIR)/libdivsufsort/lib/trsort.o + $(CC) $(SRC_LZSADIR)/matchfinder.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/matchfinder.o + $(CC) $(SRC_LZSADIR)/dictionary.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/dictionary.o + $(CC) $(SRC_LZSADIR)/expand_block_v1.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_block_v1.o + $(CC) $(SRC_LZSADIR)/expand_block_v2.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_block_v2.o + $(CC) $(SRC_LZSADIR)/expand_context.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_context.o + $(CC) $(SRC_LZSADIR)/expand_inmem.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/expand_inmem.o + $(CC) $(SRC_LZSADIR)/frame.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/frame.o + $(CC) $(SRC_LZSADIR)/shrink_block_v1.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_block_v1.o + $(CC) $(SRC_LZSADIR)/shrink_block_v2.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_block_v2.o + $(CC) $(SRC_LZSADIR)/shrink_context.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_context.o + $(CC) $(SRC_LZSADIR)/shrink_inmem.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/shrink_inmem.o + $(CC) $(SRC_LZSADIR)/stream.c $(LZSA_FLAGS) -o $(SRC_LZSADIR)/stream.o + $(CC) rasm.c $(CFLAGS_OPT) $(APU_OBJ) $(LZSA_OBJ) $(ZX0_OBJ) + strip $(EXEC) + +install: + install rasm /usr/local/bin + +clean: + rm -f $(APU_OBJ) $(LZSA_OBJ) $(ZX0_OBJ) apultra-master/src/apultra.o lzsa-master/src/shrink_streaming.o lzsa-master/src/expand_streaming.o diff --git a/tools/rasm/minilib.h b/tools/rasm/minilib.h index 99d55eb..705b982 100644 --- a/tools/rasm/minilib.h +++ b/tools/rasm/minilib.h @@ -1,9 +1,16 @@ -#define __FILENAME__ "minilib.h" +#define __FILENAME__ "minilib.h" #include #include #include +#ifdef _MSC_VER +#if _MSC_VER>1500 #include +#endif +#else +#include +#endif + #include #include #include @@ -41,12 +48,18 @@ #define MemRealloc realloc #define MemMalloc malloc #define MemMove memmove -#ifdef OS_WIN +#if defined(__BORLANDC__) +#define TxtStrDup strdup +#elif defined(OS_WIN) #define TxtStrDup _strdup #else #define TxtStrDup strdup #endif +#ifdef __BORLANDC__ +#define _setmode setmode +#endif /* __BORLANDC__ */ + #define loginfo(...); {printf(__VA_ARGS__);printf("\n");} #define logdebug(...); {printf(__VA_ARGS__);printf("\n");} #define logwarn(...); {printf(__VA_ARGS__);printf("\n");} @@ -89,7 +102,7 @@ int MinMaxInt(int zeval, int zemin, int zemax) } /* (c) FSF */ -#ifdef __WATCOMC__ +#if defined(__WATCOMC__) || defined(__BORLANDC__) size_t strnlen (s, maxlen) register const char *s; size_t maxlen; @@ -101,8 +114,63 @@ size_t strnlen (s, maxlen) ; return n; } +#define _strnlen strnlen #endif +/* +** Call syntax: char *stristr(char *String, char *Pattern) +** +** Description: This function is an ANSI version of strstr() with +** case insensitivity. +** Return item: char *pointer if Pattern is found in String, else +** pointer to 0 +** Rev History: 07/04/95 Bob Stout ANSI-fy +** 02/03/94 Fred Cole Original +** Hereby donated to public domain. +** Modified for use with libcyrus by Ken Murchison 06/01/00. +** +** from Debian package cyrus-imapd + +modified for Rasm as pattern is always upper case... + +*/ + +char *_internal_stristr(const char *ZeString, const unsigned int ZeLen, const char *Pattern) +{ + char *pptr, *sptr, *start; + unsigned int slen,plen; + + start = (char *)ZeString; + pptr = (char *)Pattern; + plen = strlen(Pattern); + slen = ZeLen; + for ( /* while string length not shorter than pattern length */; + slen >= plen; + start++, slen--) { + /* find start of pattern in string */ + while (toupper(*start) != *Pattern) { + start++; + slen--; + /* if pattern longer than string */ + if (slen < plen) + return NULL; + } + + // because pattern is always 2 or more... + sptr = start+1; + pptr = (char *)Pattern+1; + + while (toupper(*sptr) == *pptr) { + sptr++; + pptr++; + + if ('\0' == *pptr) { + return start; + } + } + } + return NULL; +} char *TxtStrDupLen(char *str, int *len) { @@ -665,15 +733,15 @@ char *_internal_fgetsmulti(char *filename, int read_mode) #define FUNC "_internal_fgetsmulti" static char buffer[MAX_LINE_BUFFER+1]={0}; FILE *last_id=NULL; - char * (*_file_get_string)(char *, int, FILE *); + char * (*_file_get_string)(char *, int, FILE *)=fgets; last_id=FileOpen(filename,"r"); switch (read_mode) { + default:logerr("Unknown read mode! (%d)",read_mode); case RAW_READING:_file_get_string=fgets;break; case CLOSE_READING:_file_get_string=_internal_fgetsClose;break; - default:logerr("Unknown read mode! (%d)",read_mode); } if (_file_get_string(buffer,MAX_LINE_BUFFER,last_id)!=NULL) @@ -709,9 +777,9 @@ char **_internal_fgetsmultilines(char *filename, int read_mode) switch (read_mode) { + default:logerr("Unknown read mode! (%d)",read_mode); case RAW_READING:_file_get_string=fgets;break; case CLOSE_READING:_file_get_string=_internal_fgetsClose;break; - default:logerr("Unknown read mode! (%d)",read_mode); } @@ -859,6 +927,31 @@ int FileReadBinary(char *filename,char *data,int n) return nn; } +/*** + FileTruncate function + set file to zero size then leave +*/ +int FileTruncate(char *filename) +{ +#undef FUNC +#define FUNC "FileTruncate" +FILE *last_id=NULL; + +#ifdef OS_WIN +int sr; +last_id=FileOpen(filename,"w"); +sr=_setmode(_fileno(last_id), _O_BINARY ); +if (sr==-1) { +logerr("FATAL: cannot set binary mode for writing"); +exit(ABORT_ERROR); +} +#else +last_id=FileOpen(filename,"a+"); +#endif +FileClose(last_id); +return 0; +} + /*** FileWriteBinary function @@ -917,6 +1010,7 @@ int FileWriteBinary(char *filename,char *data,int n) /* NULL buffer sent, this means End of file, we close the handle */ //logdebug("%d byte(s) written to %s",FileGetCPT(last_id),filename); FileClose(last_id); + nn=0; } return nn; } diff --git a/tools/rasm/msdos.bat b/tools/rasm/msdos.bat new file mode 100644 index 0000000..0962054 --- /dev/null +++ b/tools/rasm/msdos.bat @@ -0,0 +1,4 @@ +wcl386 rasm.c -6r -6s -fp6 -d0 -k4000000 -ox /bt=DOS /l=dos4g -DOS_WIN=1 -DNOAPULTRA=1 +upx.exe --brute rasm.exe + + diff --git a/tools/rasm/rasm.c b/tools/rasm/rasm.c new file mode 100644 index 0000000..88cd59c --- /dev/null +++ b/tools/rasm/rasm.c @@ -0,0 +1,24321 @@ +#define PROGRAM_NAME "RASM" +#define PROGRAM_VERSION "1.7" +#define PROGRAM_DATE "xx/11/2021" +#define PROGRAM_COPYRIGHT "© 2017 BERGE Edouard / roudoudou from Resistance" + +#define RASM_VERSION PROGRAM_NAME" v"PROGRAM_VERSION" (build "PROGRAM_DATE")" +#define RASM_SNAP_VERSION PROGRAM_NAME" v"PROGRAM_VERSION + +#define TRACE_GENERALE 0 +#define TRACE_PREPRO 0 +#define TRACE_ASSEMBLE 0 +#define TRACE_POPEXPR 0 +#define TRACE_COMPUTE_EXPRESSION 0 +#define TRACE_HEXBIN 0 +#define TRACE_MAKEAMSDOSREAL 0 +#define TRACE_STRUCT 0 +#define TRACE_EDSK 0 +#define TRACE_LABEL 0 + +/*** +Rasm (roudoudou assembler) Z80 assembler + +doc & latest official release at: https://github.com/EdouardBERGE/rasm + +You may send requests/bugs in the same topic + +----------------------------------------------------------------------------------------------------- +This software is using MIT "expat" license + +« Copyright © BERGE Edouard (roudoudou) + +Permission is hereby granted, free of charge,to any person obtaining a copy of this software +and associated documentation/source files of RASM, 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. » +----------------------------------------------------------------------------------------------------- +Linux compilation with GCC or Clang: +cc rasm.c -O2 -lm -lrt -march=native -o rasm +strip rasm + +Windows compilation with Visual studio: +cl.exe rasm.c -O2 -Ob3 + +pure MS-DOS 32 bits compilation with Watcom without native support of AP-Ultra: +wcl386 rasm.c -6r -6s -fp6 -d0 -k4000000 -ox /bt=DOS /l=dos4g -DOS_WIN=1 -DNOAPLIB=1 + +MorphOS compilation (ixemul): +gcc -noixemul -O2 -c -o rasm rasm.c +strip rasm + +MacOS compilation: +cc rasm.c -O2 -lm -march=native -o rasm + +*/ + +#ifdef __WATCOMC__ +#define OS_WIN 1 +#endif + +#ifdef _WIN32 +#define OS_WIN 1 +#endif + +#ifdef _WIN64 +#define OS_WIN 1 +#endif + +#ifndef RDD + /* public lib */ + #include"minilib.h" +#else + /* private dev lib wont be published */ + #include"../tools/library.h" + #define TxtSplitWithChar _internal_TxtSplitWithChar +#endif + +int MAX_OFFSET_ZX0=32640; + +#ifndef NO_3RD_PARTIES +#define __FILENAME__ "3rd parties" +/* 3rd parties compression */ +#include"zx7.h" +#include"lz4.h" +#include"exomizer.h" + +void zx0_reverse(unsigned char *first, unsigned char *last) { + unsigned char c; + + while (first < last) { + c = *first; + *first++ = *last; + *last-- = c; + } +} + +typedef struct block_t { + struct block_t *chain; + struct block_t *ghost_chain; + int bits; + int index; + int offset; + int references; +} BLOCK; + +BLOCK *allocate(int bits, int index, int offset, BLOCK *chain); + +void assign(BLOCK **ptr, BLOCK *chain); + +BLOCK *zx0_optimize(unsigned char *input_data, int input_size, int skip, int offset_limit); + +unsigned char *zx0_compress(BLOCK *optimal, unsigned char *input_data, int input_size, int skip, int backwards_mode, int invert_mode, int *output_size, int *delta); + +#endif + +#ifdef __MORPHOS__ +/* Add standard version string to executable */ +const char __attribute__((section(".text"))) ver_version[]={ "\0$VER: "PROGRAM_NAME" "PROGRAM_VERSION" ("PROGRAM_DATE") "PROGRAM_COPYRIGHT"" }; +/* Expand the default stack to match rasm requirements (about 64KiB) */ +unsigned long __stack = 128 * 1024; +#endif + +#undef __FILENAME__ +#define __FILENAME__ "rasm.c" + +#ifndef OS_WIN +#define KNORMAL "\x1B[0m" +#define KERROR "\x1B[31m" +#define KAYGREEN "\x1B[32m" +#define KWARNING "\x1B[33m" +#define KBLUE "\x1B[34m" +#define KVERBOSE "\x1B[36m" +#define KIO "\x1B[97m" +#else +#define KNORMAL "" +#define KERROR "Error: " +#define KAYGREEN "" +#define KWARNING "Warning: " +#define KBLUE "" +#define KVERBOSE "" +#define KIO "" +#endif + +/******************************************************************* + c o m m a n d l i n e p a r a m e t e r s +*******************************************************************/ +enum e_dependencies_type { +E_DEPENDENCIES_NO=0, +E_DEPENDENCIES_LIST, +E_DEPENDENCIES_MAKE +}; + +struct s_parameter { + char **labelfilename; + char *filename; + char *outputfilename; + int automatic_radix; + int export_local; + int export_var; + int export_equ; + int export_sym; + int export_multisym; + int export_tape; + char *flexible_export; + int export_sna; + int export_snabrk; + int export_brk; + int nowarning; + int erronwarn; + int utf8enable; + int freequote; + int checkmode; + int dependencies; + int maxerr; + int macrovoid; + int extended_error; + int display_stats; + int edskoverwrite; + int xpr; + float rough; + int as80,dams,pasmo; + int v2; + int warn_unused; + char *symbol_name; + char *binary_name; + char *cartridge_name; + char *snapshot_name; + char *rom_name; + char *tape_name; + char *breakpoint_name; + char *cprinfo_name; + char **symboldef; + int nsymb,msymb; + char **pathdef; + int npath,mpath; + int noampersand; + int cprinfo,cprinfoexport; + char module_separator; + int enforce_symbol_case; +}; + + + +/******************************************************************* + c o m p u t e o p e r a t i o n s f o r c a l c u l a t o r +*******************************************************************/ + +enum e_compute_operation_type { +E_COMPUTE_OPERATION_PUSH_DATASTC=0, +E_COMPUTE_OPERATION_OPEN=1, +E_COMPUTE_OPERATION_CLOSE=2, +E_COMPUTE_OPERATION_ADD=3, +E_COMPUTE_OPERATION_SUB=4, +E_COMPUTE_OPERATION_DIV=5, +E_COMPUTE_OPERATION_MUL=6, +E_COMPUTE_OPERATION_AND=7, +E_COMPUTE_OPERATION_OR=8, +E_COMPUTE_OPERATION_MOD=9, +E_COMPUTE_OPERATION_XOR=10, +E_COMPUTE_OPERATION_NOT=11, +E_COMPUTE_OPERATION_SHL=12, +E_COMPUTE_OPERATION_SHR=13, +E_COMPUTE_OPERATION_BAND=14, +E_COMPUTE_OPERATION_BOR=15, +E_COMPUTE_OPERATION_LOWER=16, +E_COMPUTE_OPERATION_GREATER=17, +E_COMPUTE_OPERATION_EQUAL=18, +E_COMPUTE_OPERATION_NOTEQUAL=19, +E_COMPUTE_OPERATION_LOWEREQ=20, +E_COMPUTE_OPERATION_GREATEREQ=21, +/* math functions */ +E_COMPUTE_OPERATION_SIN=22, +E_COMPUTE_OPERATION_COS=23, +E_COMPUTE_OPERATION_INT=24, +E_COMPUTE_OPERATION_FLOOR=25, +E_COMPUTE_OPERATION_ABS=26, +E_COMPUTE_OPERATION_LN=27, +E_COMPUTE_OPERATION_LOG10=28, +E_COMPUTE_OPERATION_SQRT=29, +E_COMPUTE_OPERATION_ASIN=30, +E_COMPUTE_OPERATION_ACOS=31, +E_COMPUTE_OPERATION_ATAN=32, +E_COMPUTE_OPERATION_EXP=33, +E_COMPUTE_OPERATION_LOW=34, +E_COMPUTE_OPERATION_HIGH=35, +E_COMPUTE_OPERATION_PSG=36, +E_COMPUTE_OPERATION_RND=37, +E_COMPUTE_OPERATION_FRAC=38, +E_COMPUTE_OPERATION_CEIL=39, +E_COMPUTE_OPERATION_GET_R=40, +E_COMPUTE_OPERATION_GET_V=41, +E_COMPUTE_OPERATION_GET_B=42, +E_COMPUTE_OPERATION_SET_R=43, +E_COMPUTE_OPERATION_SET_V=44, +E_COMPUTE_OPERATION_SET_B=45, +E_COMPUTE_OPERATION_SOFT2HARD=46, +E_COMPUTE_OPERATION_HARD2SOFT=47, +/* string functions */ +E_COMPUTE_OPERATION_GETNOP=48, +E_COMPUTE_OPERATION_GETTICK=49, +E_COMPUTE_OPERATION_DURATION=50, +E_COMPUTE_OPERATION_FILESIZE=51, +E_COMPUTE_OPERATION_GETSIZE=52, +E_COMPUTE_OPERATION_END=53 +}; + +struct s_compute_element { +enum e_compute_operation_type operator; +double value; +int priority; +char *string; +}; + +struct s_compute_core_data { + /* evaluator v3 may be recursive */ + char *varbuffer; + int maxivar; + struct s_compute_element *tokenstack; + int maxtokenstack; + struct s_compute_element *operatorstack; + int maxoperatorstack; +}; + +/*********************************************************** + w a v h e a d e r f o r a u d i o i m p o r t +***********************************************************/ +struct s_wav_header { +char ChunkID[4]; +unsigned char ChunkSize[4]; +char Format[4]; +char SubChunk1ID[4]; +unsigned char SubChunk1Size[4]; +unsigned char AudioFormat[2]; +unsigned char NumChannels[2]; +unsigned char SampleRate[4]; +unsigned char ByteRate[4]; +unsigned char BlockAlign[2]; +unsigned char BitsPerSample[2]; +unsigned char SubChunk2ID[4]; +unsigned char SubChunk2Size[4]; +}; + +enum e_audio_sample_type { +AUDIOSAMPLE_SMP, +AUDIOSAMPLE_SM2, +AUDIOSAMPLE_SM4, +AUDIOSAMPLE_DMAA, +AUDIOSAMPLE_DMAB, +AUDIOSAMPLE_DMAC, +AUDIOSAMPLE_END +}; + +/*********************************************************************** + e x p r e s s i o n t y p e s f o r d e l a y e d w r i t e +***********************************************************************/ +enum e_expression { + E_EXPRESSION_J8, /* relative 8bits jump */ + E_EXPRESSION_0V8, /* 8 bits value to current address */ + E_EXPRESSION_V8, /* 8 bits value to current address+1 */ + E_EXPRESSION_J16, /* 16 bits value to current address+1 */ + E_EXPRESSION_J16C, /* 16 bits value to current address+1 */ + E_EXPRESSION_V16, /* 16 bits value to current address+1 */ + //E_EXPRESSION_V16C, /* 16 bits value to current address+1 */ + E_EXPRESSION_0V16, /* 16 bits value to current address */ + E_EXPRESSION_0V32, /* 32 bits value to current address */ + E_EXPRESSION_0VR, /* AMSDOS real value (5 bytes) to current address */ + E_EXPRESSION_0VRMike,/* Microsoft IEEE-754 real value (5 bytes) to current address */ + E_EXPRESSION_IV8, /* 8 bits value to current address+2 */ + E_EXPRESSION_IV81, /* 8 bits value+1 to current address+2 */ + E_EXPRESSION_3V8, /* 8 bits value to current address+3 used with LD (IX+n),n */ + E_EXPRESSION_IV16, /* 16 bits value to current address+2 */ + E_EXPRESSION_RST, /* the offset of RST is translated to the opcode */ + E_EXPRESSION_IM, /* the interrupt mode is translated to the opcode */ + E_EXPRESSION_RUN, /* delayed RUN value */ + E_EXPRESSION_ZXRUN, /* delayed RUN value for ZX snapshot */ + E_EXPRESSION_ZXSTACK,/* delayed STACK value for ZX snapshot */ + E_EXPRESSION_BRS /* delayed shifting for BIT, RES, SET */ +}; + +struct s_expression { + char *reference; /* backup when used inside loop (or macro?) */ + int iw; /* word index in the main wordlist */ + int o; /* offset de depart 0, 1 ou 3 selon l'opcode */ + int ptr; /* offset courant pour calculs relatifs */ + int wptr; /* where to write the result */ + enum e_expression zetype; /* type of delayed write */ + int lz; /* lz zone */ + int ibank; /* ibank of expression */ + int iorgzone; /* org of expression */ + char *module; +}; + +struct s_expr_dico { + char *name; + int crc; + int autorise_export; + double v; + int used; + int iw; + int external; +}; + +struct s_external_mapping { + int iorgzone; + int ptr; + int size; + int value; // do not relocate outside scope! +}; + +struct s_external { + char *name; + int crc; + /* mapping info */ + struct s_external_mapping *mapping; + int nmapping,mmapping; +}; + +struct s_label { + char *name; /* is alloced for local repeat or struct OR generated global -> in this case iw=-1 */ + int iw; /* index of the word of label name */ + int crc; /* crc of the label name */ + int ptr; /* "physical" address */ + int lz; /* is the label in a crunched section (or after)? */ + int iorgzone; /* org of label */ + int ibank; /* current CPR bank / always zero in classic mode */ + int local; + /* errmsg */ + int fileidx; + int fileline; + int autorise_export,backidx; + int used; +}; + +struct s_alias { + char *alias; + char *translation; + int crc,len,autorise_export; + int iw,lz; + int used; + /* v1.5 */ + int ptr; + float v; +}; + +struct s_ticker { + char *varname; + int crc; + long nopstart; + long tickerstart; +}; + +/*********************************************************************** + m e r k e l t r e e s f o r l a b e l, v a r, a l i a s +***********************************************************************/ +struct s_crclabel_tree { + struct s_crclabel_tree *radix[256]; + struct s_label *label; + int nlabel,mlabel; +}; +struct s_crcdico_tree { + struct s_crcdico_tree *radix[256]; + struct s_expr_dico *dico; + int ndico,mdico; +}; +struct s_crcused_tree { + struct s_crcused_tree *radix[256]; + char **used; + int nused,mused; +}; +struct s_crcstring_tree { + struct s_crcstring_tree *radix[256]; + char **text; + int ntext,mtext; + char **replace; + int nreplace,mreplace; +}; +/************************************************* + m e m o r y s e c t i o n +*************************************************/ +struct s_lz_section { + int iw; + int memstart,memend; + int lzversion; /* 0 -> NO CRUNCH but must be delayed / 4 -> LZ4 / 7 -> ZX7 / 48 -> LZ48 / 49 -> LZ49 / 8 -> Exomizer */ + int version,minmatch; /* LZSA + ZX0 */ + int iorgzone; + int ibank; + /* idx backup */ + int iexpr; + int ilabel; +}; + +struct s_orgzone { + int ibank,protect; + int memstart,memend; + int ifile,iline; + int nocode; + int inplace; +}; + +/************************************************** + i n c b i n s t o r a g e +**************************************************/ +struct s_hexbin { + unsigned char *data; + int datalen,rawlen; + char *filename; + int crunch; + int version,minmatch; +}; + +/************************************************** + e d s k m a n a g e m e n t +**************************************************/ +struct s_edsk_sector_global_struct { +unsigned char track; +unsigned char side; +unsigned char id; +unsigned char size; +unsigned char st1; +unsigned char st2; +unsigned short int length; +unsigned char *data; +}; + +struct s_edsk_track_global_struct { +int sectornumber; +/* information purpose */ +int sectorsize; +int gap3length; +int fillerbyte; +int datarate; +int recordingmode; +struct s_edsk_sector_global_struct *sector; +}; + +struct s_edsk_global_struct { +int tracknumber; +int sidenumber; +int tracksize; /* DSK legacy */ +struct s_edsk_track_global_struct *track; +}; + +struct s_edsk_wrapper_entry { +unsigned char user; +unsigned char filename[11]; +unsigned char subcpt; +unsigned char extendcounter; +unsigned char reserved; +unsigned char rc; +unsigned char blocks[16]; +}; + +struct s_edsk_wrapper { +char *edsk_filename; +struct s_edsk_wrapper_entry entry[64]; +int nbentry; +unsigned char blocks[178][1024]; /* DATA format */ +int face; +}; + +struct s_save { + int ibank; + int ioffset; + int isize; + int iw,irun; + char *filename; + int amsdos,hobeta; + int tape,dsk,face,iwdskname; +}; + + +/******************** + L O O P S +********************/ + +enum e_loop_style { +E_LOOPSTYLE_REPEATN, +E_LOOPSTYLE_REPEATUNTIL, +E_LOOPSTYLE_WHILE +}; + +struct s_repeat { + int start; + int cpt; + int value; + int maxim; + int repeat_counter; + char *repeatvar; + double varincrement; + int repeatcrc; +}; + +struct s_whilewend { + int start; + int cpt; + int value; + int maxim; + int while_counter; +}; + +struct s_switchcase { + int refval; + int execute; + int casematch; +}; + +struct s_repeat_index { + int ifile; + int ol,oidx; + int cl,cidx; +}; + + +enum e_ifthen_type { +E_IFTHEN_TYPE_IF=0, +E_IFTHEN_TYPE_IFNOT=1, +E_IFTHEN_TYPE_IFDEF=2, +E_IFTHEN_TYPE_IFNDEF=3, +E_IFTHEN_TYPE_ELSE=4, +E_IFTHEN_TYPE_ELSEIF=5, +E_IFTHEN_TYPE_IFUSED=6, +E_IFTHEN_TYPE_IFNUSED=7, +E_IFTHEN_TYPE_END +}; + +struct s_ifthen { + char *filename; + int line,v; + enum e_ifthen_type type; +}; + +/************************************************** + w o r d p r o c e s s i n g +**************************************************/ +struct s_wordlist { + char *w; + int l,t,e; /* e=1 si egalite dans le mot */ + int ifile; +}; + +struct s_macro { + char *mnemo; + int crc; + /* une macro concatene des chaines et des parametres */ + struct s_wordlist *wc; + int nbword,maxword; + /**/ + char **param; + int nbparam; +}; + +struct s_macro_position { + int start,end,value,level,pushed; + //char *lastlocal; + //int lastlocalen,lastlocalalloc; +}; + +/* preprocessing only */ +struct s_macro_fast { + char *mnemo; + int crc; +}; + +struct s_math_keyword { + char *mnemo; + int crc; + enum e_compute_operation_type operation; +}; + +struct s_expr_word { + char *w; + int aw; + int op; + int comma; + int fct; + double v; +}; + +struct s_listing { + char *listing; + int ifile; + int iline; +}; + +enum e_tagtranslateoption { +E_TAGOPTION_NONE=0, +E_TAGOPTION_REMOVESPACE=1, +E_TAGOPTION_PRESERVE=2 +}; + +#ifdef RASM_THREAD +struct s_rasm_thread { + pthread_t thread; + int lz; + unsigned char *datain; + int datalen; + unsigned char *dataout; + int lenout; + int status; +}; +#endif + + +/********************************************************* + S N A P S H O T E X P O R T +*********************************************************/ +/* extension 4Mo = 256 slots + 4 slots 64K de RAM par défaut => 260 */ + +#define BANK_MAX_NUMBER 260 + +struct s_snapshot_symbol { + unsigned char size; + unsigned char name[256]; + unsigned char reserved[6]; + unsigned char bigendian_address[2]; +}; + + +struct s_zxsnapshot { + + unsigned int run; + unsigned int stack; +}; + +struct s_snapshot { + char idmark[8]; + char unused1[8]; + unsigned char version; /* 3 */ + struct { + struct { + unsigned char F; + unsigned char A; + unsigned char C; + unsigned char B; + unsigned char E; + unsigned char D; + unsigned char L; + unsigned char H; + }general; + unsigned char R; + unsigned char regI; /* I incompatible with tgmath.h */ + unsigned char IFF0; + unsigned char IFF1; + unsigned char LX; + unsigned char HX; + unsigned char LY; + unsigned char HY; + unsigned char LSP; + unsigned char HSP; + unsigned char LPC; + unsigned char HPC; + unsigned char IM; /* 0,1,2 */ + struct { + unsigned char F; + unsigned char A; + unsigned char C; + unsigned char B; + unsigned char E; + unsigned char D; + unsigned char L; + unsigned char H; + }alternate; + }registers; + + struct { + unsigned char selectedpen; + unsigned char palette[17]; + unsigned char multiconfiguration; + }gatearray; + unsigned char ramconfiguration; + struct { + unsigned char selectedregister; + unsigned char registervalue[18]; + }crtc; + unsigned char romselect; + struct { + unsigned char portA; + unsigned char portB; + unsigned char portC; + unsigned char control; + }ppi; + struct { + unsigned char selectedregister; + unsigned char registervalue[16]; + }psg; + unsigned char dumpsize[2]; /* 64 then use extended memory chunks */ + + unsigned char CPCType; /* 0=464 / 1=664 / 2=6128 / 4=6128+ / 5=464+ / 6=GX4000 */ + unsigned char interruptnumber; + unsigned char multimodebytes[6]; + unsigned char unused2[0x9C-0x75]; + + /* offset #9C */ + struct { + unsigned char motorstate; + unsigned char physicaltrack; + }fdd; + unsigned char unused3[3]; + unsigned char printerstrobe; + unsigned char unused4[2]; + struct { + unsigned char model; /* 0->4 */ + unsigned char unused5[4]; + unsigned char HCC; + unsigned char unused; + unsigned char CLC; + unsigned char RLC; + unsigned char VTC; + unsigned char HSC; + unsigned char VSC; + unsigned short int flags; + }crtcstate; + unsigned char vsyncdelay; + unsigned char interruptscanlinecounter; + unsigned char interruptrequestflag; + unsigned char unused6[0xFF-0xB5+1]; +}; + +struct s_snapshot_chunks { + unsigned char chunkname[4]; /* MEM1 -> MEM8 */ + unsigned int chunksize; +}; + +struct s_breakpoint { + int address; + int bank; +}; + + +/********************************* + S T R U C T U R E S +*********************************/ +enum e_rasmstructfieldtype { +E_RASMSTRUCTFIELD_BYTE, +E_RASMSTRUCTFIELD_WORD, +E_RASMSTRUCTFIELD_LONG, +E_RASMSTRUCTFIELD_REAL, +E_RASMSTRUCTFIELD_END +}; +struct s_rasmstructfield { + char *fullname; + char *name; + int offset; + int size; + int crc; + /* filler */ + unsigned char *data; + int idata,mdata; + enum e_rasmstructfieldtype zetype; +}; + +struct s_rasmstruct { + char *name; + int crc; + int size; + int ptr; + int nbelem; + /* fields */ + struct s_rasmstructfield *rasmstructfield; + int irasmstructfield,mrasmstructfield; +}; + +/********************************* + D E B U G +*********************************/ + +#define INSIDE_RASM +#include "rasm.h" + + +/******************************************* + P O K E R +*******************************************/ +enum e_poker { +E_POKER_XOR8=0, +E_POKER_SUM8=1, +E_POKER_CIPHER001=2, +E_POKER_CIPHER002=3, +E_POKER_CIPHER003=4, +E_POKER_CIPHER004=5, +E_POKER_END +}; + +char *strpoker[]={ + "XORMEM", + "SUMMEM", + "CIPHER001 running XOR initialised with first value", + "CIPHER002 running XOR initialised with memory location", + "CIPHER003 XOR with LSB of memory location", + "CIPHER004 XOR with key looping", + NULL +}; + +struct s_poker { + enum e_poker method; + int istart,iend; + int outputadr; + int ibank; + int istring; + int ipoker; +}; + +/******************************************* + G L O B A L S T R U C T +*******************************************/ +struct s_assenv { + /* current memory */ + int maxptr; + /* CPR memory */ + unsigned char **mem; + int iwnamebank[BANK_MAX_NUMBER]; + int nbbank,maxbank; + int forcetape,forcezx,forcecpr,forceROM,forceROMconcat,bankmode,activebank,amsdos,forcesnapshot,packedbank,extendedCPR,xpr,cprinfo,cprinfo_export; + char *cprinfo_filename; + struct s_snapshot snapshot; + struct s_zxsnapshot zxsnapshot; + int snapRAMsize; + int bankset[BANK_MAX_NUMBER>>2]; /* 64K selected flag */ + int bankused[BANK_MAX_NUMBER]; /* 16K selected flag */ + int bankgate[BANK_MAX_NUMBER+1]; + int setgate[BANK_MAX_NUMBER+1]; + int rundefined; + /* parsing */ + struct s_wordlist *wl; + int nbword; + int idx,stage; + char *label_filename; + int label_line; + char **filename; + int ifile,maxfile; + char **rawfile; // case export + int *rawlen; // case export + int nberr,flux; + int fastmatch[256]; + unsigned char charset[256]; + int maxerr,extended_error,nowarning,erronwarn,utf8enable,freequote; + /* ORG tracking */ + int codeadr,outputadr,nocode; + int codeadrbackup,outputadrbackup; + int minadr,maxadr; + struct s_orgzone *orgzone; + int io,mo; + /* Struct */ + struct s_rasmstruct *rasmstruct; + int irasmstruct,mrasmstruct; + int getstruct; + int backup_outputadr,backup_codeadr; + char *backup_filename; + int backup_line; + struct s_rasmstruct *rasmstructalias; + int irasmstructalias,mrasmstructalias; + /* expressions */ + struct s_expression *expression; + int ie,me; + int maxam,as80,dams,pasmo; + float rough; + struct s_compute_core_data *computectx,ctx1,ctx2; + struct s_crcstring_tree stringtree; + /* label */ + struct s_label *label; + int il,ml; + struct s_crclabel_tree labeltree; /* fast label access */ + char *module; + int modulen; + char module_separator[2]; + struct s_breakpoint *breakpoint; + int ibreakpoint,maxbreakpoint; + char *lastgloballabel; + //char *lastsuperglobal; + int lastgloballabellen, lastglobalalloc; + char **globalstack; /* retrieve back global from previous scope */ + int igs,mgs; + char *source_bigbuffer; + int source_bigbuffer_len; + /* repeat */ + struct s_repeat *repeat; + int ir,mr; + double repeat_start; + double repeat_increment; + /* while/wend */ + struct s_whilewend *whilewend; + int iw,mw; + /* if/then/else */ + //int *ifthen; + struct s_ifthen *ifthen; + int ii,mi; + /* switch/case */ + struct s_switchcase *switchcase; + int isw,msw; + /* expression dictionnary */ + struct s_expr_dico *dico; + int idic,mdic; + struct s_crcdico_tree dicotree; /* fast dico access */ + struct s_crcused_tree usedtree; /* fast used access */ + /* ticker */ + struct s_ticker *ticker; + int iticker,mticker; + long tick,nop; + /* crunch section flag */ + struct s_lz_section *lzsection; + int ilz,mlz; + int lz,curlz; + /* poker */ + struct s_poker *poker; + int nbpoker,maxpoker; + /* macro */ + struct s_macro *macro; + int imacro,mmacro; + int macrovoid; + /* labels locaux */ + int repeatcounter,whilecounter,macrocounter; + struct s_macro_position *macropos; + int imacropos,mmacropos; + /* alias */ + struct s_alias *alias; + int ialias,malias; + /* hexbin */ + struct s_rasm_thread **rasm_thread; + int irt,mrt; + struct s_hexbin *hexbin; + int ih,mh; + char **includepath; + int ipath,mpath; + /* automates */ + char AutomateExpressionValidCharExtended[256]; + char AutomateExpressionValidCharFirst[256]; + char AutomateExpressionValidChar[256]; + char AutomateExpressionDecision[256]; + char AutomateValidLabelFirst[256]; + char AutomateValidLabel[256]; + char AutomateDigit[256]; + char AutomateHexa[256]; + struct s_compute_element AutomateElement[256]; + unsigned char psgtab[256]; + unsigned char psgfine[256]; + int noampersand; + /* output */ + char *outputfilename; + int export_sym,export_local,export_multisym; + int export_var,export_equ; + int export_sna,export_snabrk; + int export_brk,export_tape; + int autorise_export; + char *flexible_export; + char *breakpoint_name; + char *symbol_name; + char *binary_name; + char *cartridge_name; + char *snapshot_name; + char *tape_name; + char *rom_name; + struct s_save *save; + int nbsave,maxsave; + int current_run_idx; + struct s_edsk_wrapper *edsk_wrapper; + int nbedskwrapper,maxedskwrapper; + int edskoverwrite; + int checkmode,dependencies; + int stop; + int warn_unused; + int display_stats; + int enforce_symbol_case; + /* debug */ + struct s_rasm_info debug; + struct s_rasm_info **retdebug; + int debug_total_len; + /* delayed print */ + int *dprint_idx; + int idprint,mdprint; + /* OBJ output */ + int buildobj; + struct s_external *external; + int nexternal,mexternal; + int external_mapping_size; + struct s_external_mapping *relocation; + int nrelocation,mrelocation; + char **procedurename; + int nprocedurename,mprocedurename; +}; + +/************************************* + D I R E C T I V E S +*************************************/ +struct s_asm_keyword { + char *mnemo; + int crc; + void (*makemnemo)(struct s_assenv *ae); +}; + +struct s_math_keyword math_keyword[]={ +{"SIN",0,E_COMPUTE_OPERATION_SIN}, +{"COS",0,E_COMPUTE_OPERATION_COS}, +{"INT",0,E_COMPUTE_OPERATION_INT}, +{"ABS",0,E_COMPUTE_OPERATION_ABS}, +{"LN",0,E_COMPUTE_OPERATION_LN}, +{"LOG10",0,E_COMPUTE_OPERATION_LOG10}, +{"SQRT",0,E_COMPUTE_OPERATION_SQRT}, +{"FLOOR",0,E_COMPUTE_OPERATION_FLOOR}, +{"ASIN",0,E_COMPUTE_OPERATION_ASIN}, +{"ACOS",0,E_COMPUTE_OPERATION_ACOS}, +{"ATAN",0,E_COMPUTE_OPERATION_ATAN}, +{"EXP",0,E_COMPUTE_OPERATION_EXP}, +{"LO",0,E_COMPUTE_OPERATION_LOW}, +{"HI",0,E_COMPUTE_OPERATION_HIGH}, +{"PSGVALUE",0,E_COMPUTE_OPERATION_PSG}, +{"RND",0,E_COMPUTE_OPERATION_RND}, +{"FRAC",0,E_COMPUTE_OPERATION_FRAC}, +{"CEIL",0,E_COMPUTE_OPERATION_CEIL}, +{"GETR",0,E_COMPUTE_OPERATION_GET_R}, +{"GETV",0,E_COMPUTE_OPERATION_GET_V}, +{"GETG",0,E_COMPUTE_OPERATION_GET_V}, +{"GETB",0,E_COMPUTE_OPERATION_GET_B}, +{"SETR",0,E_COMPUTE_OPERATION_SET_R}, +{"SETV",0,E_COMPUTE_OPERATION_SET_V}, +{"SETG",0,E_COMPUTE_OPERATION_SET_V}, +{"SETB",0,E_COMPUTE_OPERATION_SET_B}, +{"SOFT2HARD_INK",0,E_COMPUTE_OPERATION_SOFT2HARD}, +{"S2H_INK",0,E_COMPUTE_OPERATION_SOFT2HARD}, +{"HARD2SOFT_INK",0,E_COMPUTE_OPERATION_HARD2SOFT}, +{"H2S_INK",0,E_COMPUTE_OPERATION_HARD2SOFT}, +{"GETNOP",0,E_COMPUTE_OPERATION_GETNOP}, +{"GETTICK",0,E_COMPUTE_OPERATION_GETTICK}, +{"DURATION",0,E_COMPUTE_OPERATION_DURATION}, +{"FILESIZE",0,E_COMPUTE_OPERATION_FILESIZE}, +{"GETSIZE",0,E_COMPUTE_OPERATION_GETSIZE}, +{"",0,-1} +}; + +#define CRC_SWITCH 0x01AEDE4A +#define CRC_CASE 0x0826B794 +#define CRC_DEFAULT 0x9A0DAC7D +#define CRC_BREAK 0xCD364DDD +#define CRC_ENDSWITCH 0x18E9FB21 + +#define CRC_ELSEIF 0xE175E230 +#define CRC_ELSE 0x3FF177A1 +#define CRC_ENDIF 0xCD5265DE +#define CRC_IF 0x4BD52507 +#define CRC_IFDEF 0x4CB29DD6 +#define CRC_UNDEF 0xCCD2FDEA +#define CRC_IFNDEF 0xD9AD0824 +#define CRC_IFNOT 0x4CCAC9F8 +#define CRC_WHILE 0xBC268FF1 +#define CRC_UNTIL 0xCC12A604 +#define CRC_MEND 0xFFFD899C +#define CRC_ENDM 0x3FF9559C +#define CRC_MACRO 0x64AA85EA +#define CRC_IFUSED 0x91752638 +#define CRC_IFNUSED 0x1B39A886 + +#define CRC_SIN 0xE1B71962 +#define CRC_COS 0xE077C55D + +#define CRC_0 0x7A98A6A8 +#define CRC_1 0x7A98A6A9 +#define CRC_2 0x7A98A6AA + + +#define CRC_NC 0x4BD52B09 +#define CRC_Z 0x7A98A6D2 +#define CRC_NZ 0x4BD52B20 +#define CRC_P 0x7A98A6C8 +#define CRC_PO 0x4BD53717 +#define CRC_PE 0x4BD5370D +#define CRC_M 0x7A98A6C5 + +/* cut registers */ +#define CRC_HL_LOW 0xF9FDE22C +#define CRC_HL_HIGH 0x2261E25A +#define CRC_DE_LOW 0x3A3CE221 +#define CRC_DE_HIGH 0x23D0E04F +#define CRC_BC_LOW 0xFDFF1E1D +#define CRC_BC_HIGH 0x222BE44B +#define CRC_IX_LOW 0xB9FD0439 +#define CRC_IX_HIGH 0xA3FD0667 +#define CRC_IY_LOW 0xD9ED6C3A +#define CRC_IY_HIGH 0x23DD5068 +#define CRC_AF_LOW 0xDDCF141F +#define CRC_AF_HIGH 0x223FEA4D + +/* 8 bits registers */ +#define CRC_F 0x7A98A6BE +#define CRC_I 0x7A98A6C1 +#define CRC_R 0x7A98A6CA +#define CRC_A 0x7A98A6B9 +#define CRC_B 0x7A98A6BA +#define CRC_C 0x7A98A6BB +#define CRC_D 0x7A98A6BC +#define CRC_E 0x7A98A6BD +#define CRC_H 0x7A98A6C0 +#define CRC_L 0x7A98A6C4 +/* dual naming */ +#define CRC_XH 0x4BD50718 +#define CRC_XL 0x4BD5071C +#define CRC_YH 0x4BD50519 +#define CRC_YL 0x4BD5051D +#define CRC_HX 0x4BD52718 +#define CRC_LX 0x4BD52F1C +#define CRC_HY 0x4BD52719 +#define CRC_LY 0x4BD52F1D +#define CRC_IXL 0xE19F1765 +#define CRC_IXH 0xE19F1761 +#define CRC_IYL 0xE19F1166 +#define CRC_IYH 0xE19F1162 + +/* 16 bits registers */ +#define CRC_BC 0x4BD5D2FD +#define CRC_DE 0x4BD5DF01 +#define CRC_HL 0x4BD5270C +#define CRC_IX 0x4BD52519 +#define CRC_IY 0x4BD5251A +#define CRC_SP 0x4BD5311B +#define CRC_AF 0x4BD5D4FF +/* memory convention */ +#define CRC_MHL 0xD0765F5D +#define CRC_MDE 0xD0467D52 +#define CRC_MBC 0xD05E694E +#define CRC_MIX 0xD072B76A +#define CRC_MIY 0xD072B16B +#define CRC_MSP 0xD01A876C +#define CRC_MC 0xE018210C +/* struct parsing */ +#define CRC_DEFB 0x37D15389 +#define CRC_DB 0x4BD5DEFE +#define CRC_DEFW 0x37D1539E +#define CRC_DW 0x4BD5DF13 +#define CRC_DEFI 0x37D15390 +#define CRC_DEFS 0x37D1539A +#define CRC_DS 0x4BD5DF0F +#define CRC_DEFR 0x37D15399 +#define CRC_DR 0x4BD5DF0E +#define CRC_DEFF 0x37D1538D +#define CRC_DF 0x4BD5DF02 + +/* struct declaration use special instructions for defines */ +int ICRC_DEFB,ICRC_DEFW,ICRC_DEFI,ICRC_DEFR,ICRC_DEFF,ICRC_DF,ICRC_DEFS,ICRC_DB,ICRC_DW,ICRC_DR,ICRC_DS; +/* need to pre-declare var */ +extern struct s_asm_keyword instruction[]; + +/* +# base=16 +% base=2 +0-9 base=10 +A-Z variable ou fonction (cos, sin, tan, sqr, pow, mod, and, xor, mod, ...) ++*-/&^m| operateur +*/ + +#define AutomateExpressionValidCharExtendedDefinition "0123456789.ABCDEFGHIJKLMNOPQRSTUVWXYZ_{}@+-*/~^$#%<=>|&" /* § */ +#define AutomateExpressionValidCharFirstDefinition "#%0123456789.ABCDEFGHIJKLMNOPQRSTUVWXYZ_@${" +#define AutomateExpressionValidCharDefinition "0123456789.ABCDEFGHIJKLMNOPQRSTUVWXYZ_{}@$" +#define AutomateValidLabelFirstDefinition ".ABCDEFGHIJKLMNOPQRSTUVWXYZ_@" +#define AutomateValidLabelDefinition "0123456789.ABCDEFGHIJKLMNOPQRSTUVWXYZ_@{}" +#define AutomateDigitDefinition ".0123456789" +#define AutomateHexaDefinition "0123456789ABCDEF" + +#ifndef NO_3RD_PARTIES +unsigned char *LZ4_crunch(unsigned char *data, int zelen, int *retlen){ + unsigned char *lzdest=NULL; + lzdest=MemMalloc(65536); + *retlen=LZ4_compress_HC((char*)data,(char*)lzdest,zelen,65536,9); + return lzdest; +} +#ifndef NOAPULTRA +size_t apultra_compress(const unsigned char *pInputData, unsigned char *pOutBuffer, size_t nInputSize, size_t nMaxOutBufferSize, + const unsigned int nFlags, size_t nMaxWindowSize, size_t nDictionarySize, void(*progress)(long long nOriginalSize, long long nCompressedSize), void *pStats); +size_t apultra_get_max_compressed_size(size_t nInputSize); + +int do_apultra(unsigned char *datain, int lenin, unsigned char **dataout, int *lenout) { + size_t nCompressedSize = 0L, nMaxCompressedSize; + int nFlags = 0; + //apultra_stats stats; + unsigned char *pCompressedData; + + /* Allocate max compressed size */ + + nMaxCompressedSize = apultra_get_max_compressed_size(lenin); + pCompressedData = (unsigned char*)MemMalloc(nMaxCompressedSize); + memset(pCompressedData, 0, nMaxCompressedSize); + + nCompressedSize = apultra_compress(datain, pCompressedData, lenin, nMaxCompressedSize, nFlags, 65536, 0 /* dico */, NULL /*compression_progress*/, NULL /*&stats*/); + + if (nCompressedSize == -1) { + fprintf(stderr, "APULTRA compression error\n"); + *lenout=0; + *dataout=NULL; + return 100; + } + + *lenout=nCompressedSize; + *dataout=pCompressedData; + return 0; +} +int APULTRA_crunch(unsigned char *data, int len, unsigned char **dataout, int *lenout) { + return do_apultra(data, len, dataout, lenout); +} + + +size_t lzsa_compress_inmem(unsigned char *pInputData, unsigned char *pOutBuffer, size_t nInputSize, size_t nMaxOutBufferSize, + const unsigned int nFlags, const int nMinMatchSize, const int nFormatVersion); + +int LZSA_crunch(unsigned char *datain, int lenin, unsigned char **dataout, int *lenout, int version, int matchsize) { + size_t nCompressedSize = 0L, nMaxCompressedSize; + int nFlags = 0; + unsigned char *pCompressedData; + +pCompressedData=(unsigned char *)MemMalloc(65536); +nMaxCompressedSize=65536; + +/* RAW */ +nFlags=1<<1; // nFlags=LZSA_FLAG_RAW_BLOCK; +/* par défaut du LZSA1-Fast */ +if (version<1 || version>2) { + version=1; +} +if (matchsize<2 || matchsize>5) { + switch (version) { + case 1:matchsize=5;break; + case 2:matchsize=2;break; + default:break; + } +} + +nCompressedSize=lzsa_compress_inmem(datain, pCompressedData, lenin, nMaxCompressedSize, nFlags, matchsize, version); + + if (nCompressedSize == -1) { + fprintf(stderr, "LZSA compression error\n"); + *lenout=0; + *dataout=NULL; + return 100; + } + + *lenout=nCompressedSize; + *dataout=pCompressedData; + return 0; +} + +#endif +#endif + +unsigned char *LZ48_encode_legacy(unsigned char *data, int length, int *retlength); +#define LZ48_crunch LZ48_encode_legacy +unsigned char *LZ49_encode_legacy(unsigned char *data, int length, int *retlength); +#define LZ49_crunch LZ49_encode_legacy + + +/* + * optimised reading of text file in one shot + */ +unsigned char *_internal_readbinaryfile(char *filename, int *filelength) +{ + #undef FUNC + #define FUNC "_internal_readbinaryfile" + + unsigned char *binary_data=NULL; + + *filelength=FileGetSize(filename); + binary_data=MemMalloc((*filelength)+1); + /* we try to read one byte more to close the file just after the read func */ + if (FileReadBinary(filename,(char*)binary_data,(*filelength)+1)!=*filelength) { + logerr("Cannot fully read %s",filename); + exit(INTERNAL_ERROR); + } + return binary_data; +} +char **_internal_readtextfile(struct s_assenv *ae,char *filename, char replacechar) +{ + #undef FUNC + #define FUNC "_internal_readtextfile" + + char **lines_buffer=NULL; + unsigned char *bigbuffer; + int nb_lines=0,max_lines=0,i=0,e=0; + int file_size; + + bigbuffer=_internal_readbinaryfile(filename,&file_size); + + while (i=max_lines) { + max_lines=max_lines*2+10; + lines_buffer=MemRealloc(lines_buffer,(max_lines+1)*sizeof(char **)); + } + lines_buffer[nb_lines]=MemMalloc(e-i+1); + memcpy(lines_buffer[nb_lines],bigbuffer+i,e-i); + lines_buffer[nb_lines][e-i]=0; + if (0) + { + int yy; + for (yy=0;lines_buffer[nb_lines][yy];yy++) { + if (lines_buffer[nb_lines][yy]>31) printf("%c",lines_buffer[nb_lines][yy]); else printf("(0x%X)",lines_buffer[nb_lines][yy]); + } + printf("\n"); + } + nb_lines++; + i=e; + } + if (!max_lines) { + lines_buffer=MemMalloc(sizeof(char**)); + lines_buffer[0]=NULL; + } else { + lines_buffer[nb_lines]=NULL; + } + + if (ae->enforce_symbol_case && replacechar==':') { + ae->source_bigbuffer=bigbuffer; + ae->source_bigbuffer_len=file_size; + } + //MemFree(bigbuffer); + return lines_buffer; +} + +#define FileReadLines(ae,filename) _internal_readtextfile(ae,filename,':') +#define FileReadLinesRAW(ae,filename) _internal_readtextfile(ae,filename,0x0D) +#define FileReadContent(filename,filesize) _internal_readbinaryfile(filename,filesize) + + +/*** + TxtReplace + + input: + in_str: string where replace will occur + in_substr: substring to look for + out_substr: replace substring + recurse: loop until no in_substr is found + + note: in_str MUST BE previously mallocated if out_substr is bigger than in_substr +*/ +#ifndef RDD +char *TxtReplace(char *in_str, char *in_substr, char *out_substr, int recurse) +{ + #undef FUNC + #define FUNC "TxtReplace" + + char *str_look,*m1,*m2; + char *out_str; + int sl,l1,l2,dif,cpt; + + if (in_str==NULL) + return NULL; + + sl=strlen(in_str); + l1=strlen(in_substr); + /* empty string, nothing to do except return empty string */ + if (!sl || !l1) + return in_str; + + l2=strlen(out_substr); + dif=l2-l1; + + /* replace string is small or equal in size, we dont realloc */ + if (dif<=0) + { + /* we loop while there is a replace to do */ + str_look=strstr(in_str,in_substr); + while (str_look!=NULL) + { + /* we copy the new string if his len is not null */ + if (l2) + memcpy(str_look,out_substr,l2); + /* only if len are different */ + if (l1!=l2) + { + /* we move the end of the string byte per byte + because memory locations overlap. This is + faster than memmove */ + m1=str_look+l1; + m2=str_look+l2; + while (*m1!=0) + { + *m2=*m1; + m1++;m2++; + } + /* we must copy the EOL */ + *m2=*m1; + } + /* look for next replace */ + if (!recurse) + str_look=strstr(str_look+l2,in_substr); + else + str_look=strstr(in_str,in_substr); + } + out_str=in_str; + } + else + { + /* we need to count each replace */ + cpt=0; + str_look=strstr(in_str,in_substr); + while (str_look!=NULL) + { + cpt++; + str_look=strstr(str_look+l1,in_substr); + } + /* is there anything to do? */ + if (cpt) + { + /* we realloc to a size that will fit all replaces */ + out_str=MemRealloc(in_str,sl+1+dif*cpt); + str_look=strstr(out_str,in_substr); + while (str_look!=NULL && cpt) + { + /* as the replace string is bigger we + have to move memory first from the end */ + m1=out_str+sl; + m2=m1+dif; + sl+=dif; + while (m1!=str_look+l1-dif) + { + *m2=*m1; + m1--;m2--; + } + /* then we copy the replace string (can't be NULL in this case) */ + memcpy(str_look,out_substr,l2); + + /* look for next replace */ + if (!recurse) + str_look=strstr(str_look+l2,in_substr); + else + str_look=strstr(in_str,in_substr); + + /* to prevent from naughty overlap */ + cpt--; + } + if (str_look!=NULL) + { + printf("INTERNAL ERROR - overlapping replace string (%s/%s), you can't use this one!\n",in_substr,out_substr); + exit(ABORT_ERROR); + } + } + else + out_str=in_str; + } + return out_str; +} +#endif + +#ifndef min +#define min(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a < _b ? _a : _b; }) +#endif + +/* Levenshtein implementation by TheRayTracer https://gist.github.com/TheRayTracer/2644387 */ +int _internal_LevenshteinDistance(char *s, char *t) +{ + int i,j,n,m,*d; + int im,jn; + int r; + + n=strlen(s)+1; + m=strlen(t)+1; + d=malloc(n*m*sizeof(int)); + memset(d, 0, sizeof(int) * n * m); + + for (i = 1, im = 0; i < m; i++, im++) + { + for (j = 1, jn = 0; j < n; j++, jn++) + { + if (s[jn] == t[im]) + { + d[(i * n) + j] = d[((i - 1) * n) + (j - 1)]; + } + else + { + d[(i * n) + j] = min(d[(i - 1) * n + j] + 1, /* A deletion. */ + min(d[i * n + (j - 1)] + 1, /* An insertion. */ + d[(i - 1) * n + (j - 1)] + 1)); /* A substitution. */ + } + } + } + r = d[n * m - 1]; + free(d); + return r; +} + +unsigned int FastRand() +{ + #undef FUNC + #define FUNC "FastRand" + static unsigned int zeseed=0x12345678; + zeseed=214013*zeseed+2531011; + return (zeseed>>16)&0x7FFF; +} + + +#ifdef RASM_THREAD +/* + threads used for crunching +*/ +void _internal_ExecuteThreads(struct s_assenv *ae,struct s_rasm_thread *rasm_thread, void *(*fct)(void *)) +{ + #undef FUNC + #define FUNC "_internal_ExecuteThreads" + + pthread_attr_t attr; + void *status; + int rc; + /* launch threads */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE); + pthread_attr_setstacksize(&attr,65536); + + if ((rc=pthread_create(&image_threads[i].thread,&attr,fct,(void *)rasm_thread))) { + rasm_printf(ae,"FATAL ERROR - Cannot create thread!\n"); + exit(INTERNAL_ERROR); + } +} +void _internal_WaitForThreads(struct s_assenv *ae,struct s_rasm_thread *rasm_thread) +{ + #undef FUNC + #define FUNC "_internal_WaitForThreads" + int rc; + + if ((rc=pthread_join(rasm_thread->thread,&status))) { + rasm_printf(ae,"FATAL ERROR - Cannot wait for thread\n"); + exit(INTERNAL_ERROR); + } +} +void PushCrunchedFile(struct s_assenv *ae, unsigned char *datain, int datalen, int lz) +{ + #undef FUNC + #define FUNC "PushCrunchedFile" + + struct s_rasm_thread *rasm_thread; + + rasm_thread=MemMalloc(sizeof(struct s_rasm_thread)); + memset(rasm_thread,0,sizeof(struct s_rasm_thread)); + rasm_thread->datain=datain; + rasm_thread->datalen=datalen; + rasm_thread->lz=lz; + _internal_ExecuteThreads(ae,rasm_thread, void *(*fct)(void *)); + ObjectArrayAddDynamicValueConcat((void**)&ae->rasm_thread,&ae->irt,&ae->mrt,&rasm_thread,sizeof(struct s_rasm_thread *)); +} +void PopAllCrunchedFiles(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "PopAllCrunchedFiles" + + int i; + for (i=0;iirt;i++) { + _internal_WaitForThreads(ae,ae->rasm_thread[i]); + } +} +#endif + +void MaxError(struct s_assenv *ae); + +void rasm_printf(struct s_assenv *ae, ...) { + #undef FUNC + #define FUNC "(internal) rasm_printf" + + char *format; + va_list argptr; + + if (!ae->flux && !ae->dependencies) { + va_start(argptr,ae); + format=va_arg(argptr,char *); + vfprintf(stdout,format,argptr); + va_end(argptr); + fprintf(stdout,KNORMAL); + } +} +/*** + build the string of current line for error messages +*/ +char *rasm_getline(struct s_assenv *ae, int offset) { + #undef FUNC + #define FUNC "rasm_getline" + + static char myline[40]={0}; + int idx=0,icopy,first=1; + + while (!ae->wl[ae->idx+offset].t && idx<32) { + for (icopy=0;idx<32 && ae->wl[ae->idx+offset].w[icopy];icopy++) { + myline[idx++]=ae->wl[ae->idx+offset].w[icopy]; + } + if (!first) myline[idx++]=','; else first=0; + offset++; + } + if (idx>=32) { + strcpy(myline+29,"..."); + } else { + myline[idx++]=0; + } + + return myline; +} + +char *SimplifyPath(char *filename) { + #undef FUNC + #define FUNC "SimplifyPath" + + return filename; +#if 0 + char *pos,*repos; + int i,len; + + char *rpath; + + rpath=realpath(filename,NULL); + if (!rpath) { + printf("rpath error!\n"); + switch (errno) { + case EACCES:printf("read permission failure\n");break; + case EINVAL:printf("wrong argument\n");break; + case EIO:printf("I/O error\n");break; + case ELOOP:printf("too many symbolic links\n");break; + case ENAMETOOLONG:printf("names too long\n");break; + case ENOENT:printf("names does not exists\n");break; + case ENOMEM:printf("out of memory\n");break; + case ENOTDIR:printf("a component of the path is not a directory\n");break; + default:printf("unknown error\n");break; + } + exit(1); + } + if (strlen(rpath)=filename) { + if (*repos=='\\') { + break; + } + repos--; + } + repos++; + if (repos>=filename && repos!=pos) { + len=strlen(pos)-4+1; + pos+=4; + for (i=0;i=filename) { + if (*repos=='/') { + break; + } + repos--; + } + repos++; + if (repos>=filename && repos!=pos) { + len=strlen(pos)-4+1; + pos+=4; + for (i=0;i=0 && filename[idx]!='\\') idx--; + if (idx<0) { + /* pas de chemin */ + strcpy(curpath,".\\"); + } else { + /* chemin trouve */ + strcpy(curpath,filename); + curpath[idx+1]=0; + } +#else +#ifdef __MORPHOS__ + #define CURRENT_DIR "" +#else + #define CURRENT_DIR "./" +#endif + idx=zelen-1; + while (idx>=0 && filename[idx]!='/') idx--; + if (idx<0) { + /* pas de chemin */ + strcpy(curpath,CURRENT_DIR); + } else { + /* chemin trouve */ + strcpy(curpath,filename); + curpath[idx+1]=0; + } +#endif + + return curpath; +} +char *MergePath(struct s_assenv *ae,char *dadfilename, char *filename) { + #undef FUNC + #define FUNC "MergePath" + + static char curpath[PATH_MAX]; + + +#ifdef OS_WIN + TxtReplace(filename,"/","\\",1); + + if (filename[0] && filename[1]==':' && filename[2]=='\\') { + /* chemin absolu */ + strcpy(curpath,filename); + } else if (filename[0] && filename[1]==':') { + rasm_printf(ae,KERROR"unsupported path style [%s]\n",filename); + exit(-111); + } else { + if (filename[0]=='.' && filename[1]=='\\') { + strcpy(curpath,rasm_GetPath(dadfilename)); + strcat(curpath,filename+2); + } else { + strcpy(curpath,rasm_GetPath(dadfilename)); + strcat(curpath,filename); + } + } +#else + if (filename[0]=='/') { + /* chemin absolu */ + strcpy(curpath,filename); + } else if (filename[0]=='.' && filename[1]=='/') { + strcpy(curpath,rasm_GetPath(dadfilename)); + strcat(curpath,filename+2); + } else { + strcpy(curpath,rasm_GetPath(dadfilename)); + strcat(curpath,filename); + } +#endif + + return curpath; +} + + +void InitAutomate(char *autotab, const unsigned char *def) +{ + #undef FUNC + #define FUNC "InitAutomate" + + int i; + + memset(autotab,0,256); + for (i=0;def[i];i++) { + autotab[(unsigned int)def[i]]=1; + } +} +void StateMachineResizeBuffer(char **ABuf, int idx, int *ASize) { + #undef FUNC + #define FUNC "StateMachineResizeBuffer" + + if (idx>=*ASize) { + if (*ASize<16384) { + *ASize=(*ASize)*2; + } else { + *ASize=(*ASize)+16384; + } + *ABuf=MemRealloc(*ABuf,(*ASize)+2); + } +} + +int GetCRC(char *label) +{ + #undef FUNC + #define FUNC "GetCRC" + int crc=0x12345678; + int i=0; + + while (label[i]!=0) { + crc=(crc<<9)^(crc+label[i++]); + } + return crc; +} + +int IsDirective(char *expr); + +int IsRegister(char *zeexpression) +{ + #undef FUNC + #define FUNC "IsRegister" + + switch (GetCRC(zeexpression)) { + case CRC_F:if (strcmp(zeexpression,"F")==0) return 1; else return 0; + case CRC_I:if (strcmp(zeexpression,"I")==0) return 1; else return 0; + case CRC_R:if (strcmp(zeexpression,"R")==0) return 1; else return 0; + case CRC_A:if (strcmp(zeexpression,"A")==0) return 1; else return 0; + case CRC_B:if (strcmp(zeexpression,"B")==0) return 1; else return 0; + case CRC_C:if (strcmp(zeexpression,"C")==0) return 1; else return 0; + case CRC_D:if (strcmp(zeexpression,"D")==0) return 1; else return 0; + case CRC_E:if (strcmp(zeexpression,"E")==0) return 1; else return 0; + case CRC_H:if (strcmp(zeexpression,"H")==0) return 1; else return 0; + case CRC_L:if (strcmp(zeexpression,"L")==0) return 1; else return 0; + case CRC_BC:if (strcmp(zeexpression,"BC")==0) return 1; else return 0; + case CRC_DE:if (strcmp(zeexpression,"DE")==0) return 1; else return 0; + case CRC_HL:if (strcmp(zeexpression,"HL")==0) return 1; else return 0; + case CRC_IX:if (strcmp(zeexpression,"IX")==0) return 1; else return 0; + case CRC_IY:if (strcmp(zeexpression,"IY")==0) return 1; else return 0; + case CRC_SP:if (strcmp(zeexpression,"SP")==0) return 1; else return 0; + case CRC_AF:if (strcmp(zeexpression,"AF")==0) return 1; else return 0; + case CRC_XH:if (strcmp(zeexpression,"XH")==0) return 1; else return 0; + case CRC_XL:if (strcmp(zeexpression,"XL")==0) return 1; else return 0; + case CRC_YH:if (strcmp(zeexpression,"YH")==0) return 1; else return 0; + case CRC_YL:if (strcmp(zeexpression,"YL")==0) return 1; else return 0; + case CRC_HX:if (strcmp(zeexpression,"HX")==0) return 1; else return 0; + case CRC_LX:if (strcmp(zeexpression,"LX")==0) return 1; else return 0; + case CRC_HY:if (strcmp(zeexpression,"HY")==0) return 1; else return 0; + case CRC_LY:if (strcmp(zeexpression,"LY")==0) return 1; else return 0; + case CRC_IXL:if (strcmp(zeexpression,"IXL")==0) return 1; else return 0; + case CRC_IXH:if (strcmp(zeexpression,"IXH")==0) return 1; else return 0; + case CRC_IYL:if (strcmp(zeexpression,"IYL")==0) return 1; else return 0; + case CRC_IYH:if (strcmp(zeexpression,"IYH")==0) return 1; else return 0; + default:break; + } + return 0; +} + +int StringIsMem(char *w) +{ + #undef FUNC + #define FUNC "StringIsMem" + + int p=1,idx=1; + + if (w[0]=='(') { + while (w[idx]) { + switch (w[idx]) { + case '\\':if (w[idx+1]) idx++; + break; + case '\'':if (w[idx+1] && w[idx+1]!='\\') idx++; + break; + case '(':p++;break; + case ')':p--; + /* si on sort de la première parenthèse */ + if (!p && w[idx+1]) return 0; + break; + default:break; + } + idx++; + } + /* si on ne termine pas par une parenthèse */ + if (w[idx-1]!=')') return 0; + } else { + return 0; + } + return 1; + +} + + +int StringIsQuote(char *w) +{ + #undef FUNC + #define FUNC "StringIsQuote" + + int i,tquote,lens; + + if (w[0]=='\'' || w[0]=='"') { + tquote=w[0]; + lens=strlen(w); + + /* est-ce bien une chaine et uniquement une chaine? */ + i=1; + while (w[i] && w[i]!=tquote) { + if (w[i]=='\\') i++; + i++; + } + if (i==lens-1) { + return tquote; + } + } + return 0; +} +char *StringLooksLikeDicoRecurse(struct s_crcdico_tree *lt, int *score, char *str) +{ + #undef FUNC + #define FUNC "StringLooksLikeDicoRecurse" + + char *retstr=NULL,*tmpstr; + int i,curs; + + for (i=0;i<256;i++) { + if (lt->radix[i]) { + tmpstr=StringLooksLikeDicoRecurse(lt->radix[i],score,str); + if (tmpstr!=NULL) retstr=tmpstr; + } + } + if (lt->mdico) { + for (i=0;indico;i++) { + if (strlen(lt->dico[i].name)>4) { + curs=_internal_LevenshteinDistance(str,lt->dico[i].name); + if (curs<*score) { + *score=curs; + retstr=lt->dico[i].name; + } + } + } + } + return retstr; +} +char *StringLooksLikeDico(struct s_assenv *ae, int *score, char *str) +{ + #undef FUNC + #define FUNC "StringLooksLikeDico" + + char *retstr=NULL,*tmpstr; + int i; + + for (i=0;i<256;i++) { + if (ae->dicotree.radix[i]) { + tmpstr=StringLooksLikeDicoRecurse(ae->dicotree.radix[i],score,str); + if (tmpstr!=NULL) retstr=tmpstr; + } + } + return retstr; +} +char *StringLooksLikeMacro(struct s_assenv *ae, char *str, int *retscore) +{ + #undef FUNC + #define FUNC "StringLooksLikeMacro" + + char *ret=NULL; + int i,curs,score=3; + /* search in macros */ + for (i=0;iimacro;i++) { + curs=_internal_LevenshteinDistance(ae->macro[i].mnemo,str); + if (cursmacro[i].mnemo; + } + } + if (retscore) *retscore=score; + return ret; +} + +char *StringLooksLike(struct s_assenv *ae, char *str) +{ + #undef FUNC + #define FUNC "StringLooksLike" + + char *ret=NULL,*tmpret; + int i,curs,score=4; + + /* search in variables */ + ret=StringLooksLikeDico(ae,&score,str); + + /* search in labels */ + for (i=0;iil;i++) { + if (!ae->label[i].name && strlen(ae->wl[ae->label[i].iw].w)>4) { + curs=_internal_LevenshteinDistance(ae->wl[ae->label[i].iw].w,str); + if (curswl[ae->label[i].iw].w; + } + } + } + + /* search in alias */ + for (i=0;iialias;i++) { + if (strlen(ae->alias[i].alias)>4) { + curs=_internal_LevenshteinDistance(ae->alias[i].alias,str); + if (cursalias[i].alias; + } + } + } + + tmpret=StringLooksLikeMacro(ae,str,&curs); + if (cursflux) { + /* in embedded Rasm all errors are stored in a debug struct */ + struct s_debug_error curerror; + char toosmalltotakeitall[2]={0}; + int myalloc; + char *errstr; + + va_start(argptr,format); + myalloc=vsnprintf(toosmalltotakeitall,1,format,argptr); + va_end(argptr); + + #if defined(_MSC_VER) && _MSC_VER < 1900 + /* visual studio before 2015 does not fully support C99 */ + if (myalloc<1 && strlen(format)) { + va_start(argptr,format); + myalloc=_vscprintf(format,argptr); + va_end(argptr); + } + #endif + if (myalloc<1) { + /* does not crash */ + return; + } + + va_start(argptr,format); + errstr=MemMalloc(myalloc+1); + vsnprintf(errstr,myalloc,format,argptr); + curerror.msg=errstr; + curerror.lenmsg=myalloc; + curerror.line=line; + if (filename) curerror.filename=TxtStrDupLen(filename,&curerror.lenfilename); else curerror.filename=TxtStrDupLen("",&curerror.lenfilename); + ObjectArrayAddDynamicValueConcat((void **)&ae->debug.error,&ae->debug.nberror,&ae->debug.maxerror,&curerror,sizeof(struct s_debug_error)); + va_end(argptr); + } else { + fprintf(stdout,KERROR); + if (filename && line) { + printf("[%s:%d] ",filename,line); + } else if (filename) { + printf("[%s] ",filename); + } + va_start(argptr,format); + vfprintf(stdout,format,argptr); + va_end(argptr); + fprintf(stdout,KNORMAL); + } +} + +/* convert v double value to Microsoft REAL + * + * https://en.wikipedia.org/wiki/Microsoft_Binary_Format + * + * exponent:8 + * sign:1 + * mantiss:23 + * + * */ +unsigned char *__internal_MakeRosoftREAL(struct s_assenv *ae, double v, int iexpression) +{ + #undef FUNC + #define FUNC "__internal_MakeRosoftREAL" + + static unsigned char orc[5]={0}; + unsigned char rc[5]={0}; + int j,ib,ibb; + int fracmax=0; + int mesbits[32]; + int ibit=0,exp=0; + // v2 + unsigned long mantissa; + unsigned long deci; + unsigned long mask; + int isneg; + + if (v<0.0) {isneg=1;v=-v;} else isneg=0; + + memset(rc,0,sizeof(rc)); + + // decimal hack + deci=v; +#if TRACE_MAKEAMSDOSREAL +printf("AmstradREAL decimal part is %s\n",doubletext); +#endif + /******************************************************************* + values >= 1.0 + *******************************************************************/ + if (deci) { + mask=0x80000000; + // find first significant bit of decimal part in order to get exponent value + while (!(deci & mask)) mask=mask/2; + while (mask) { + exp++; + mask=mask/2; + } + mantissa=v*pow(2.0,32-exp)+0.5; // 32 bits unsigned is the maximum value allowed + if (mantissa & 0xFF00000000L) mantissa=0xFFFFFFFF; +#if TRACE_MAKEAMSDOSREAL +printf("decimal part has %d bits\n",exp); +printf("32 bits mantissa is %lu\n",mantissa); +#endif + mask=0x80000000; + while (mask) { + mesbits[ibit]=!!(mantissa & mask); + ibit++; + mask=mask/2; + } + } else { + /******************************************************************* + negative exponent or zero + *******************************************************************/ + /* handling zero special case */ + if (v==0.0) { + exp=-128; + ibit=0; + } else { + mantissa=(v*4294967296.0+0.5); // as v is ALWAYS <1.0 we never reach the 32 bits maximum + if (mantissa & 0xFF00000000L) mantissa=0xFFFFFFFF; + mask=0x80000000; +#if TRACE_MAKEAMSDOSREAL +printf("32 bits mantissa for fraction is %lu\n",mantissa); +#endif + // find first significant bit of fraction part + while (!(mantissa & mask)) { + mask=mask/2; + exp--; + } + + mantissa=(v*pow(2.0,32-exp)+0.5); // as v is ALWAYS <1.0 we never reach the 32 bits maximum + if (mantissa & 0xFF00000000L) mantissa=0xFFFFFFFF; + mask=0x80000000; + + while (mask && ibit<32) { + mesbits[ibit]=!!(mantissa & mask); + ibit++; + mask=mask/2; + } + } +#if TRACE_MAKEAMSDOSREAL +printf("\n%d bits used for mantissa\n",ibit); +#endif + } + + /* pack bits */ + ib=3;ibb=0x80; + for (j=0;j>=1; + if (ibb==0) { + ibb=0x80; + ib--; + } + } + /* exponent */ + exp+=128; + if (exp<0 || exp>255) { + if (iexpression) MakeError(ae,GetExpFile(ae,iexpression),ae->wl[ae->expression[iexpression].iw].l,"Exponent overflow\n"); + else MakeError(ae,GetExpFile(ae,0),ae->wl[ae->idx].l,"Exponent overflow\n"); + exp=128; + } + rc[4]=exp; + + /* Microsoft REAL sign */ + if (!isneg) { + rc[3]&=0x7F; + } else { + rc[3]|=0x80; + } + + /* switch byte order */ + orc[0]=rc[4]; + orc[1]=rc[3]; + orc[2]=rc[2]; + orc[3]=rc[1]; + orc[4]=rc[0]; + +#if TRACE_MAKEAMSDOSREAL + for (j=0;j<5;j++) printf("%02X ",orc[j]); + printf("\n"); +#endif + + return orc; +} + + +/* convert v double value to Amstrad REAL + * + * http://www.cpcwiki.eu/index.php?title=Technical_information_about_Locomotive_BASIC&mobileaction=toggle_view_desktop#Floating_Point_data_definition + * + * exponent:8 + * sign:1 + * mantiss:23 + * + * */ +unsigned char *__internal_MakeAmsdosREAL(struct s_assenv *ae, double v, int iexpression) +{ + #undef FUNC + #define FUNC "__internal_MakeAmsdosREAL" + + static unsigned char rc[5]; + int mesbits[32]={0}; // must be reseted! + int j,ib,ibb; + int ibit=0,exp=0; + // v2 + unsigned long mantissa; + unsigned long deci; + unsigned long mask; + int isneg; + + memset(rc,0,sizeof(rc)); + + if (v<0.0) {isneg=1;v=-v;} else isneg=0; + + // decimal hack + deci=v; +#if TRACE_MAKEAMSDOSREAL +printf("AmstradREAL decimal part is %s\n",doubletext); +#endif + /******************************************************************* + values >= 1.0 + *******************************************************************/ + if (deci) { + mask=0x80000000; + // find first significant bit of decimal part in order to get exponent value + while (!(deci & mask)) mask=mask/2; + while (mask) { + exp++; + mask=mask/2; + } + mantissa=v*pow(2.0,32-exp)+0.5; // 32 bits unsigned is the maximum value allowed + if (mantissa & 0xFF00000000L) mantissa=0xFFFFFFFF; +#if TRACE_MAKEAMSDOSREAL +printf("decimal part has %d bits\n",exp); +printf("32 bits mantissa is %lu\n",mantissa); +#endif + mask=0x80000000; + while (mask) { + mesbits[ibit]=!!(mantissa & mask); + ibit++; + mask=mask/2; + } + } else { + /******************************************************************* + negative exponent or zero + *******************************************************************/ + /* handling zero special case */ + if (v==0.0) { + exp=-128; + } else { + mantissa=(v*4294967296.0+0.5); // as v is ALWAYS <1.0 we never reach the 32 bits maximum + if (mantissa & 0xFF00000000L) mantissa=0xFFFFFFFF; + mask=0x80000000; +#if TRACE_MAKEAMSDOSREAL +printf("32 bits mantissa for fraction is %lu\n",mantissa); +#endif + // find first significant bit of fraction part + while (!(mantissa & mask)) { + mask=mask/2; + exp--; + } + + mantissa=(v*pow(2.0,32-exp)+0.5); // as v is ALWAYS <1.0 we never reach the 32 bits maximum + if (mantissa & 0xFF00000000L) mantissa=0xFFFFFFFF; + mask=0x80000000; + + while (mask) { + mesbits[ibit]=!!(mantissa & mask); + ibit++; + mask=mask/2; + } + } +#if TRACE_MAKEAMSDOSREAL +printf("\n%d bits used for mantissa\n",ibit); +#endif + } + + /* pack bits */ + ib=3;ibb=0x80; + for (j=0;j255) { + if (iexpression) MakeError(ae,GetExpFile(ae,iexpression),ae->wl[ae->expression[iexpression].iw].l,"Exponent overflow\n"); + else MakeError(ae,GetExpFile(ae,0),ae->wl[ae->idx].l,"Exponent overflow\n"); + exp=128; + } + rc[4]=exp; + + /* REAL sign replace the most significant implied bit */ + if (!isneg) { + rc[3]&=0x7F; + } else { + rc[3]|=0x80; + } + +#if TRACE_MAKEAMSDOSREAL + for (j=0;j<5;j++) printf("%02X ",rc[j]); + printf("\n------------------\n"); +#endif + + return rc; +} + + + + +struct s_label *SearchLabel(struct s_assenv *ae, char *label, int crc); +char *GetExpFile(struct s_assenv *ae,int didx){ + #undef FUNC + #define FUNC "GetExpFile" + + if (ae->label_filename) { + return ae->label_filename; + } + if (didx<0) { + return ae->filename[ae->wl[-didx].ifile]; + } else if (!didx) { + return ae->filename[ae->wl[ae->idx].ifile]; + } else if (ae->expression && didxie) { + return ae->filename[ae->wl[ae->expression[didx].iw].ifile]; + } else { + //return ae->filename[ae->wl[ae->idx].ifile]; + return 0; + } +} + +int GetExpLine(struct s_assenv *ae,int didx){ + #undef FUNC + #define FUNC "GetExpLine" + + if (ae->label_line) return ae->label_line; + + if (didx<0) { + return ae->wl[-didx].l; + } else if (!didx) { + return ae->wl[ae->idx].l; + } else if (didxie) { + return ae->wl[ae->expression[didx].iw].l; + } else return 0; +} + +char *GetCurrentFile(struct s_assenv *ae) +{ + return GetExpFile(ae,0); +} + + +/******************************************************************************************* + M E M O R Y C L E A N U P +*******************************************************************************************/ +void FreeLabelTree(struct s_assenv *ae); +void FreeDicoTree(struct s_assenv *ae); +void FreeUsedTree(struct s_assenv *ae); +void ExpressionFastTranslate(struct s_assenv *ae, char **ptr_expr, int fullreplace); +char *TradExpression(char *zexp); + + +void _internal_RasmFreeInfoStruct(struct s_rasm_info *debug) +{ + #undef FUNC + #define FUNC "RasmFreeInfoStruct" + + int i; + if (debug->maxerror) { + for (i=0;inberror;i++) { + MemFree(debug->error[i].filename); + MemFree(debug->error[i].msg); + } + MemFree(debug->error); + } + if (debug->maxsymbol) { + for (i=0;inbsymbol;i++) { + MemFree(debug->symbol[i].name); + } + MemFree(debug->symbol); + } +} + +void RasmFreeInfoStruct(struct s_rasm_info *debug) +{ + _internal_RasmFreeInfoStruct(debug); + MemFree(debug); +} + +void FreeAssenv(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "FreeAssenv" + int i,j; + +#ifndef RDD + /* let the system free the memory in command line except when debug/dev */ + #ifndef __MORPHOS__ + /* MorphOS does not like when memory is not freed before exit */ + if (!ae->flux) return; + #endif +#endif + /*** debug info ***/ + if (!ae->retdebug) { + _internal_RasmFreeInfoStruct(&ae->debug); + } else { + /* symbols */ + struct s_debug_symbol debug_symbol={0}; + + for (i=0;iil;i++) { + /* on exporte tout */ + if (!ae->label[i].name) { + /* les labels entiers */ + debug_symbol.name=TxtStrDup(ae->wl[ae->label[i].iw].w); + debug_symbol.v=ae->label[i].ptr; + ObjectArrayAddDynamicValueConcat((void**)&ae->debug.symbol,&ae->debug.nbsymbol,&ae->debug.maxsymbol,&debug_symbol,sizeof(struct s_debug_symbol)); + } else { + /* les labels locaux et générés */ + debug_symbol.name=TxtStrDup(ae->label[i].name); + debug_symbol.v=ae->label[i].ptr; + ObjectArrayAddDynamicValueConcat((void**)&ae->debug.symbol,&ae->debug.nbsymbol,&ae->debug.maxsymbol,&debug_symbol,sizeof(struct s_debug_symbol)); + } + } + for (i=0;iialias;i++) { + if (strcmp(ae->alias[i].alias,"IX") && strcmp(ae->alias[i].alias,"IY")) { + debug_symbol.name=TxtStrDup(ae->alias[i].alias); + debug_symbol.v=RoundComputeExpression(ae,ae->alias[i].translation,0,0,0); + ObjectArrayAddDynamicValueConcat((void**)&ae->debug.symbol,&ae->debug.nbsymbol,&ae->debug.maxsymbol,&debug_symbol,sizeof(struct s_debug_symbol)); + } + } + + /* export struct */ + *ae->retdebug=MemMalloc(sizeof(struct s_rasm_info)); + memcpy(*ae->retdebug,&ae->debug,sizeof(struct s_rasm_info)); + } + /*** end debug ***/ + + if (ae->enforce_symbol_case) { + for (i=0;iifile;i++) { + if (ae->rawlen[i]) MemFree(ae->rawfile[i]); + } + } + + for (i=0;inbbank;i++) { + MemFree(ae->mem[i]); + } + MemFree(ae->mem); + + /* expression core buffer free */ + ComputeExpressionCore(NULL,NULL,0,0); + ExpressionFastTranslate(NULL,NULL,0); + /* free labels, expression, orgzone, repeat, ... */ + if (ae->mo) MemFree(ae->orgzone); + if (ae->me) { + for (i=0;iie;i++) { + if (ae->expression[i].reference) MemFree(ae->expression[i].reference); + if (ae->expression[i].module) MemFree(ae->expression[i].module); + } + MemFree(ae->expression); + } + if (ae->nbsave) { + for (i=0;inbsave;i++) { + if (ae->save[i].filename) MemFree(ae->save[i].filename); + } + } + if (ae->mh) { + for (i=0;iih;i++) { + //MemFree(ae->hexbin[i].data); + MemFree(ae->hexbin[i].filename); + } + MemFree(ae->hexbin); + } + for (i=0;iil;i++) { + if (ae->label[i].name && ae->label[i].iw==-1) MemFree(ae->label[i].name); + } + /* structures */ + for (i=0;iirasmstructalias;i++) { + MemFree(ae->rasmstructalias[i].name); + } + if (ae->mrasmstructalias) MemFree(ae->rasmstructalias); + + for (i=0;iirasmstruct;i++) { + for (j=0;jrasmstruct[i].irasmstructfield;j++) { + MemFree(ae->rasmstruct[i].rasmstructfield[j].fullname); + MemFree(ae->rasmstruct[i].rasmstructfield[j].name); + if (ae->rasmstruct[i].rasmstructfield[j].mdata) MemFree(ae->rasmstruct[i].rasmstructfield[j].data); + } + if (ae->rasmstruct[i].mrasmstructfield) MemFree(ae->rasmstruct[i].rasmstructfield); + MemFree(ae->rasmstruct[i].name); + } + if (ae->mrasmstruct) MemFree(ae->rasmstruct); + + /* other */ + if (ae->maxbreakpoint) MemFree(ae->breakpoint); + if (ae->ml) MemFree(ae->label); + if (ae->mr) MemFree(ae->repeat); + if (ae->mi) MemFree(ae->ifthen); + if (ae->msw) MemFree(ae->switchcase); + if (ae->mw) MemFree(ae->whilewend); + if (ae->modulen || ae->module) { + MemFree(ae->module); + } + /* deprecated + for (i=0;iidic;i++) { + MemFree(ae->dico[i].name); + } + if (ae->mdic) MemFree(ae->dico); + */ + if (ae->mlz) MemFree(ae->lzsection); + + for (i=0;iifile;i++) { + MemFree(ae->filename[i]); + } + MemFree(ae->filename); + + for (i=0;iimacro;i++) { + if (ae->macro[i].maxword) MemFree(ae->macro[i].wc); + for (j=0;jmacro[i].nbparam;j++) MemFree(ae->macro[i].param[j]); + if (ae->macro[i].nbparam) MemFree(ae->macro[i].param); + } + + + if (ae->mmacro) MemFree(ae->macro); + + for (i=0;iigs;i++) { + if (ae->globalstack[i]) MemFree(ae->globalstack[i]); + } + if (ae->mgs) MemFree(ae->globalstack); + if (ae->lastglobalalloc) { + MemFree(ae->lastgloballabel); + ae->lastglobalalloc=0; + ae->lastgloballabel=NULL; + } + + /* external + mapping */ + for (i=0;inexternal;i++) { + if (ae->external[i].mmapping) MemFree(ae->external[i].mapping); + } + if (ae->mexternal) MemFree(ae->external); + + for (i=0;iialias;i++) { + MemFree(ae->alias[i].alias); + MemFree(ae->alias[i].translation); + } + if (ae->malias) MemFree(ae->alias); + + for (i=0;ae->wl[i].t!=2;i++) { + MemFree(ae->wl[i].w); + } + MemFree(ae->wl); + + if (ae->ctx1.varbuffer) { + MemFree(ae->ctx1.varbuffer); + } + if (ae->ctx1.maxtokenstack) { + MemFree(ae->ctx1.tokenstack); + } + if (ae->ctx1.maxoperatorstack) { + MemFree(ae->ctx1.operatorstack); + } + if (ae->ctx2.varbuffer) { + MemFree(ae->ctx2.varbuffer); + } + if (ae->ctx2.maxtokenstack) { + MemFree(ae->ctx2.tokenstack); + } + if (ae->ctx2.maxoperatorstack) { + MemFree(ae->ctx2.operatorstack); + } + + for (i=0;iiticker;i++) { + MemFree(ae->ticker[i].varname); + } + if (ae->mticker) MemFree(ae->ticker); + + MemFree(ae->outputfilename); + FreeLabelTree(ae); + FreeDicoTree(ae); + FreeUsedTree(ae); + if (ae->mmacropos) MemFree(ae->macropos); + TradExpression(NULL); + MemFree(ae); +} + + + +void MaxError(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "MaxError" + + char **source_lines=NULL; + int zeline; + + + /* extended error is useful with generated code we do not want to edit */ + if (ae->extended_error && ae->wl) { + /* super dupper slow but anyway, there is an error... */ + if (ae->wl[ae->idx].l) { + source_lines=FileReadLinesRAW(ae,GetCurrentFile(ae)); + zeline=0; + while (zelinewl[ae->idx].l-1 && source_lines[zeline]) zeline++; + if (zeline==ae->wl[ae->idx].l-1 && source_lines[zeline]) { + rasm_printf(ae,KAYGREEN"-> %s",source_lines[zeline]); + } else { + rasm_printf(ae,KERROR"cannot read line %d of file [%s]\n",ae->wl[ae->idx].l,GetCurrentFile(ae)); + } + FreeArrayDynamicValue(&source_lines); + } + } + + ae->nberr++; + if (ae->nberr==ae->maxerr) { + rasm_printf(ae,KERROR"Too many errors!\n"); + FreeAssenv(ae); + exit(ae->nberr); + } +} + +void (*___output)(struct s_assenv *ae, unsigned char v); + +void ___internal_output_disabled(struct s_assenv *ae,unsigned char v) +{ + #undef FUNC + #define FUNC "fake ___output" +} +void ___internal_output(struct s_assenv *ae,unsigned char v) +{ + #undef FUNC + #define FUNC "___output" + + if (ae->outputadrmaxptr) { + ae->mem[ae->activebank][ae->outputadr++]=v; + ae->codeadr++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"output exceed limit %d\n",ae->maxptr); + ae->stop=1; + ___output=___internal_output_disabled; + } +} +void ___internal_output_nocode(struct s_assenv *ae,unsigned char v) +{ + #undef FUNC + #define FUNC "___output (nocode)" + + if (ae->outputadrmaxptr) { + /* struct definition always in NOCODE */ + if (ae->getstruct) { + int irs,irsf; + irs=ae->irasmstruct-1; + irsf=ae->rasmstruct[irs].irasmstructfield-1; + + /* ajouter les data du flux au champ de la structure */ + ObjectArrayAddDynamicValueConcat((void**)&ae->rasmstruct[irs].rasmstructfield[irsf].data, + &ae->rasmstruct[irs].rasmstructfield[irsf].idata, + &ae->rasmstruct[irs].rasmstructfield[irsf].mdata, + &v,sizeof(unsigned char)); + } + + ae->outputadr++; + ae->codeadr++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"output exceed limit %d\n",ae->maxptr); + ae->stop=1; + ___output=___internal_output_disabled; + } +} + + +void ___output_set_limit(struct s_assenv *ae,int zelimit) +{ + #undef FUNC + #define FUNC "___output_set_limit" + + int limit=65536; + + if (zelimit<=limit) { + /* apply limit */ + limit=zelimit; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"limit exceed hardware limitation!"); + ae->stop=1; + } + if (ae->outputadr>=0 && ae->outputadr>=limit) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"limit too high for current output!"); + ae->stop=1; + } + ae->maxptr=limit; +} + +unsigned char *MakeAMSDOSHeader(int run, int minmem, int maxmem, char *amsdos_name) { + #undef FUNC + #define FUNC "MakeAMSDOSHeader" + + static unsigned char AmsdosHeader[128]; + int checksum,i=0; + /*** cpcwiki + Byte 00: User number + Byte 01 to 08: filename + Byte 09 bis 11: Extension + Byte 18: type-byte + Byte 21 and 22: loading address + Byte 24 and 25: file length + Byte 26 and 27: execution address for machine code programs + Byte 64 and 65: (file length) + Byte 67 and 68: checksum for byte 00 to byte 66 + To calculate the checksum, just add byte 00 to byte 66 to each other. + */ + memset(AmsdosHeader,0,sizeof(AmsdosHeader)); + AmsdosHeader[0]=0; + memcpy(AmsdosHeader+1,amsdos_name,11); + + AmsdosHeader[18]=2; /* 0 basic 1 basic protege 2 binaire */ + AmsdosHeader[19]=(maxmem-minmem)&0xFF; + AmsdosHeader[20]=(maxmem-minmem)>>8; + AmsdosHeader[21]=minmem&0xFF; + AmsdosHeader[22]=minmem>>8; + AmsdosHeader[24]=AmsdosHeader[19]; + AmsdosHeader[25]=AmsdosHeader[20]; + AmsdosHeader[26]=run&0xFF; + AmsdosHeader[27]=run>>8; + AmsdosHeader[64]=AmsdosHeader[19]; + AmsdosHeader[65]=AmsdosHeader[20]; + AmsdosHeader[66]=0; + + for (i=checksum=0;i<=66;i++) { + checksum+=AmsdosHeader[i]; + } + AmsdosHeader[67]=checksum&0xFF; + AmsdosHeader[68]=checksum>>8; + + /* garbage / shadow values from sector buffer? */ + memcpy(AmsdosHeader+0x47,amsdos_name,8); + AmsdosHeader[0x4F]=0x24; + AmsdosHeader[0x50]=0x24; + AmsdosHeader[0x51]=0x24; + AmsdosHeader[0x52]=0xFF; + AmsdosHeader[0x54]=0xFF; + AmsdosHeader[0x57]=0x02; + AmsdosHeader[0x5A]=AmsdosHeader[21]; + AmsdosHeader[0x5B]=AmsdosHeader[22]; + AmsdosHeader[0x5D]=AmsdosHeader[24]; + AmsdosHeader[0x5E]=AmsdosHeader[25]; + + sprintf((char *)AmsdosHeader+0x47+17," created by %-9.9s ",RASM_SNAP_VERSION); + + return AmsdosHeader; +} + +unsigned char *MakeHobetaHeader(int minmem, int maxmem, char *trdos_name) { + #undef FUNC + #define FUNC "MakeHobetaHeader" + + static unsigned char HobetaHeader[17]; + int i,checksum=0; + /*** http://rk.nvg.ntnu.no/sinclair/faq/fileform.html#HOBETA + 0x00 FileName 0x08 TR-DOS file name + 0x08 FileType 0x01 TR-DOS file type + 0x09 StartAdr 0x02 start address of file + 0x0A FlLength 0x02 length of file (in bytes) -> /!\ wrong offset!!! + 0x0C FileSize 0x02 size of file (in sectors) + 0x0E HdrCRC16 0x02 Control checksum of the 15 byte + header (not sector data!) + */ + memset(HobetaHeader,0,sizeof(HobetaHeader)); + + strncpy((char*)&HobetaHeader[0],trdos_name,8); + HobetaHeader[8]='C'; + HobetaHeader[0x9]=(maxmem-minmem)&0xFF; + HobetaHeader[0xA]=(maxmem-minmem)>>8; + + HobetaHeader[0xB]=(maxmem-minmem)&0xFF; + HobetaHeader[0xC]=(maxmem-minmem)>>8; + + HobetaHeader[0xD]=((maxmem-minmem)+255)>>8; + HobetaHeader[0xE]=0; + + for (i=0;i<0xF;i++) checksum+=HobetaHeader[i]*257+i; + + HobetaHeader[0xF]=checksum&0xFF; + HobetaHeader[0x10]=(checksum>>8)&0xFF; + + return HobetaHeader; +} + + +int cmpAmsdosentry(const void * a, const void * b) +{ + return memcmp(a,b,32); +} + +int cmpmacros(const void * a, const void * b) +{ + struct s_macro *sa,*sb; + sa=(struct s_macro *)a; + sb=(struct s_macro *)b; + if (sa->crccrc) return -1; else return 1; +} +int SearchAlias(struct s_assenv *ae, int crc, char *zemot) +{ + int dw,dm,du,i; +//printf("SearchAlias [%s] ",zemot); + /* inutile de tourner autour du pot pour un si petit nombre */ + if (ae->ialias<5) { + for (i=0;iialias;i++) { + if (ae->alias[i].crc==crc && strcmp(ae->alias[i].alias,zemot)==0) { + ae->alias[i].used=1; +//printf("found\n"); + return i; + } + } +//printf("not found\n"); + return -1; + } + + dw=0; + du=ae->ialias-1; + while (dw<=du) { + dm=(dw+du)/2; + if (ae->alias[dm].crc==crc) { + /* chercher le premier de la liste */ + while (dm>0 && ae->alias[dm-1].crc==crc) dm--; + /* controle sur le texte entier */ + while (ae->alias[dm].crc==crc && strcmp(ae->alias[dm].alias,zemot)) dm++; + if (ae->alias[dm].crc==crc && strcmp(ae->alias[dm].alias,zemot)==0) { + ae->alias[dm].used=1; +//printf("[%s] found => [%s]\n",zemot,ae->alias[dm].translation); + return dm; + } else return -1; + } else if (ae->alias[dm].crc>crc) { + du=dm-1; + } else if (ae->alias[dm].crcimacro<5) { + for (i=0;iimacro;i++) { + if (ae->macro[i].crc==crc && strcmp(ae->macro[i].mnemo,zemot)==0) { + return i; + } + } + return -1; + } + + dw=0; + du=ae->imacro-1; + while (dw<=du) { + dm=(dw+du)/2; + if (ae->macro[dm].crc==crc) { + /* chercher le premier de la liste */ + while (dm>0 && ae->macro[dm-1].crc==crc) dm--; + /* controle sur le texte entier */ + while (ae->macro[dm].crc==crc && strcmp(ae->macro[dm].mnemo,zemot)) dm++; + if (ae->macro[dm].crc==crc && strcmp(ae->macro[dm].mnemo,zemot)==0) return dm; else return -1; + } else if (ae->macro[dm].crc>crc) { + du=dm-1; + } else if (ae->macro[dm].crcialias-1;i++) { + /* is there previous aliases in the new alias? */ + if (strstr(ae->alias[ae->ialias-1].translation,ae->alias[i].alias)) { + /* there is a match, apply alias translation */ + ExpressionFastTranslate(ae,&ae->alias[ae->ialias-1].translation,2); + /* need to compute again len */ + ae->alias[ae->ialias-1].len=strlen(ae->alias[ae->ialias-1].translation); + break; + } + } + + /* cas particuliers pour insertion en début ou fin de liste */ + if (ae->ialias-1) { + if (ae->alias[ae->ialias-1].crc>ae->alias[ae->ialias-2].crc) { + /* pas de tri il est déjà au bon endroit */ + } else if (ae->alias[ae->ialias-1].crcalias[0].crc) { + /* insertion tout en bas de liste */ + tmpalias=ae->alias[ae->ialias-1]; + MemMove(&ae->alias[1],&ae->alias[0],sizeof(struct s_alias)*(ae->ialias-1)); + ae->alias[0]=tmpalias; + } else { + /* on cherche ou inserer */ + crc=ae->alias[ae->ialias-1].crc; + dw=0; + du=ae->ialias-1; + while (dw<=du) { + dm=(dw+du)/2; + if (ae->alias[dm].crc==crc) { + break; + } else if (ae->alias[dm].crc>crc) { + du=dm-1; + } else if (ae->alias[dm].crcalias[dm].crcalias[ae->ialias-1]; + MemMove(&ae->alias[dm+1],&ae->alias[dm],sizeof(struct s_alias)*(ae->ialias-1-dm)); + ae->alias[dm]=tmpalias; + } + } else { + /* one alias need no sort */ + } +} + +void InsertDicoToTree(struct s_assenv *ae, struct s_expr_dico *dico) +{ + #undef FUNC + #define FUNC "InsertDicoToTree" + + struct s_crcdico_tree *curdicotree; + int radix,dek=32; + + curdicotree=&ae->dicotree; + while (dek) { + dek=dek-8; + radix=(dico->crc>>dek)&0xFF; + if (curdicotree->radix[radix]) { + curdicotree=curdicotree->radix[radix]; + } else { + curdicotree->radix[radix]=MemMalloc(sizeof(struct s_crcdico_tree)); + curdicotree=curdicotree->radix[radix]; + memset(curdicotree,0,sizeof(struct s_crcdico_tree)); + } + } + ObjectArrayAddDynamicValueConcat((void**)&curdicotree->dico,&curdicotree->ndico,&curdicotree->mdico,dico,sizeof(struct s_expr_dico)); +} + +unsigned char *SnapshotDicoInsert(char *symbol_name, int ptr, int *retidx) +{ + static unsigned char *subchunk=NULL; + static int subchunksize=0; + static int idx=0; + int symbol_len; + + if (retidx) { + if (symbol_name && strcmp(symbol_name,"FREE")==0) { + subchunksize=0; + idx=0; + MemFree(subchunk); + subchunk=NULL; + } + *retidx=idx; + return subchunk; + } + + if (idx+65536>subchunksize) { + subchunksize=subchunksize+65536; + subchunk=MemRealloc(subchunk,subchunksize); + } + + symbol_len=strlen(symbol_name); + if (symbol_len>255) symbol_len=255; + subchunk[idx++]=symbol_len; + memcpy(subchunk+idx,symbol_name,symbol_len); + idx+=symbol_len; + memset(subchunk+idx,0,6); + idx+=6; + subchunk[idx++]=(ptr&0xFF00)/256; + subchunk[idx++]=ptr&0xFF; + return NULL; +} + +void SnapshotDicoTreeRecurse(struct s_crcdico_tree *lt) +{ + #undef FUNC + #define FUNC "SnapshottDicoTreeRecurse" + + int i; + + for (i=0;i<256;i++) { + if (lt->radix[i]) { + SnapshotDicoTreeRecurse(lt->radix[i]); + } + } + if (lt->mdico) { + for (i=0;indico;i++) { + if (strcmp(lt->dico[i].name,"IX") && strcmp(lt->dico[i].name,"IY") && strcmp(lt->dico[i].name,"PI") && strcmp(lt->dico[i].name,"ASSEMBLER_RASM")) { + SnapshotDicoInsert(lt->dico[i].name,(int)floor(lt->dico[i].v+0.5),NULL); + } + } + } +} +unsigned char *SnapshotDicoTree(struct s_assenv *ae, int *retidx) +{ + #undef FUNC + #define FUNC "SnapshotDicoTree" + + unsigned char *sc; + int idx; + int i; + + for (i=0;i<256;i++) { + if (ae->dicotree.radix[i]) { + SnapshotDicoTreeRecurse(ae->dicotree.radix[i]); + } + } + + sc=SnapshotDicoInsert(NULL,0,&idx); + *retidx=idx; + return sc; +} + +void WarnLabelTreeRecurse(struct s_assenv *ae, struct s_crclabel_tree *lt) +{ + #undef FUNC + #define FUNC "WarnLabelTreeRecurse" + + int i; + + for (i=0;i<256;i++) { + if (lt->radix[i]) { + WarnLabelTreeRecurse(ae,lt->radix[i]); + } + } + for (i=0;inlabel;i++) { + if (!lt->label[i].used) { + if (!lt->label[i].name) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: label %s declared but not used\n",ae->filename[lt->label[i].fileidx],lt->label[i].fileline,ae->wl[lt->label[i].iw].w); + if (ae->erronwarn) MaxError(ae); + } else { + rasm_printf(ae,KWARNING"[%s:%d] Warning: label %s declared but not used\n",ae->filename[lt->label[i].fileidx],lt->label[i].fileline,lt->label[i].name); + if (ae->erronwarn) MaxError(ae); + } + } + } +} +void WarnLabelTree(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "WarnLabelTree" + + int i; + + for (i=0;i<256;i++) { + if (ae->labeltree.radix[i]) { + WarnLabelTreeRecurse(ae,ae->labeltree.radix[i]); + } + } +} +void WarnDicoTreeRecurse(struct s_assenv *ae, struct s_crcdico_tree *lt) +{ + #undef FUNC + #define FUNC "WarnDicoTreeRecurse" + + int i; + + + for (i=0;i<256;i++) { + if (lt->radix[i]) { + WarnDicoTreeRecurse(ae,lt->radix[i]); + } + } + for (i=0;indico;i++) { + if (strcmp(lt->dico[i].name,"IX") && strcmp(lt->dico[i].name,"IY") && strcmp(lt->dico[i].name,"PI") && strcmp(lt->dico[i].name,"ASSEMBLER_RASM") && lt->dico[i].autorise_export) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: variable %s declared but not used\n",ae->filename[ae->wl[lt->dico[i].iw].ifile],ae->wl[lt->dico[i].iw].l,lt->dico[i].name); + if (ae->erronwarn) MaxError(ae); + } + } +} +void WarnDicoTree(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "ExportDicoTree" + + int i; + + for (i=0;i<256;i++) { + if (ae->dicotree.radix[i]) { + WarnDicoTreeRecurse(ae,ae->dicotree.radix[i]); + } + } +} +void ExportDicoTreeRecurse(struct s_crcdico_tree *lt, char *zefile, char *zeformat) +{ + #undef FUNC + #define FUNC "ExportDicoTreeRecurse" + + char symbol_line[1024]; + int i; + + for (i=0;i<256;i++) { + if (lt->radix[i]) { + ExportDicoTreeRecurse(lt->radix[i],zefile,zeformat); + } + } + if (lt->mdico) { + for (i=0;indico;i++) { + if (strcmp(lt->dico[i].name,"IX") && strcmp(lt->dico[i].name,"IY") && strcmp(lt->dico[i].name,"PI") && strcmp(lt->dico[i].name,"ASSEMBLER_RASM") && lt->dico[i].autorise_export) { + snprintf(symbol_line,sizeof(symbol_line)-1,zeformat,lt->dico[i].name,(int)floor(lt->dico[i].v+0.5)); + symbol_line[sizeof(symbol_line)-1]=0xD; + FileWriteLine(zefile,symbol_line); + } + } + } +} +void ExportDicoTreeRecurseCase(struct s_assenv *ae,struct s_crcdico_tree *lt, char *zefile, char *zeformat) +{ + #undef FUNC + #define FUNC "ExportDicoTreeRecurseCase" + + char symbol_line[512]; + char symbol_name[512]; + int i; + + for (i=0;i<256;i++) { + if (lt->radix[i]) { + ExportDicoTreeRecurseCase(ae,lt->radix[i],zefile,zeformat); + } + } + if (lt->mdico) { + for (i=0;indico;i++) { + if (strcmp(lt->dico[i].name,"IX") && strcmp(lt->dico[i].name,"IY") && strcmp(lt->dico[i].name,"PI") && strcmp(lt->dico[i].name,"ASSEMBLER_RASM") && lt->dico[i].autorise_export) { + // case search + char *casefound; + int namelen; + + if ((casefound=_internal_stristr(ae->rawfile[ae->wl[lt->dico[i].iw].ifile],ae->rawlen[ae->wl[lt->dico[i].iw].ifile],lt->dico[i].name))!=NULL) { + namelen=strlen(lt->dico[i].name); + if (namelen>511) namelen=511; + memcpy(symbol_name,casefound,namelen); + symbol_name[namelen]=0; + snprintf(symbol_line,sizeof(symbol_line)-1,zeformat,symbol_name,(int)floor(lt->dico[i].v+0.5)); + } else { + snprintf(symbol_line,sizeof(symbol_line)-1,zeformat,lt->dico[i].name,(int)floor(lt->dico[i].v+0.5)); + } + symbol_line[sizeof(symbol_line)-1]=0xD; + FileWriteLine(zefile,symbol_line); + } + } + } +} +void ExportDicoTree(struct s_assenv *ae, char *zefile, char *zeformat) +{ + #undef FUNC + #define FUNC "ExportDicoTree" + + int i; + + if (!ae->enforce_symbol_case) { + for (i=0;i<256;i++) { + if (ae->dicotree.radix[i]) { + ExportDicoTreeRecurse(ae->dicotree.radix[i],zefile,zeformat); + } + } + } else { + for (i=0;i<256;i++) { + if (ae->dicotree.radix[i]) { + ExportDicoTreeRecurseCase(ae,ae->dicotree.radix[i],zefile,zeformat); + } + } + } +} +void FreeDicoTreeRecurse(struct s_crcdico_tree *lt) +{ + #undef FUNC + #define FUNC "FreeDicoTreeRecurse" + + int i; + + for (i=0;i<256;i++) { + if (lt->radix[i]) { + FreeDicoTreeRecurse(lt->radix[i]); + } + } + if (lt->mdico) { + for (i=0;indico;i++) { + MemFree(lt->dico[i].name); + } + MemFree(lt->dico); + } + MemFree(lt); +} +void FreeDicoTree(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "FreeDicoTree" + + int i; + + for (i=0;i<256;i++) { + if (ae->dicotree.radix[i]) { + FreeDicoTreeRecurse(ae->dicotree.radix[i]); + } + } + if (ae->dicotree.mdico) { + for (i=0;idicotree.ndico;i++) MemFree(ae->dicotree.dico[i].name); + MemFree(ae->dicotree.dico); + } +} +struct s_expr_dico *SearchDico(struct s_assenv *ae, char *dico, int crc) +{ + #undef FUNC + #define FUNC "SearchDico" + + struct s_crcdico_tree *curdicotree; + int i,radix,dek=32; + + curdicotree=&ae->dicotree; + + while (dek) { + dek=dek-8; + radix=(crc>>dek)&0xFF; + if (curdicotree->radix[radix]) { + curdicotree=curdicotree->radix[radix]; + } else { + /* radix not found, dico is not in index */ + return NULL; + } + } + for (i=0;indico;i++) { + if (strcmp(curdicotree->dico[i].name,dico)==0) { + curdicotree->dico[i].used=1; + + if (curdicotree->dico[i].external) { + if (ae->external_mapping_size) { + /* outside crunched section of in intermediate section */ + if (ae->lz<1 || ae->lzsection[ae->ilz-1].lzversion==0) { + // add mapping + struct s_external_mapping mapping; + int iex; + mapping.iorgzone=ae->io-1; + mapping.ptr=ae->outputadr; + mapping.size=ae->external_mapping_size; + for (iex=0;iexnexternal;iex++) { + if (ae->external[iex].crc==crc && strcmp(ae->external[iex].name,dico)==0) { + //printf("add mapping for [%s] ptr=%d size=%d\n",dico,mapping.ptr,mapping.size); + ObjectArrayAddDynamicValueConcat((void **)&ae->external[iex].mapping,&ae->external[iex].nmapping,&ae->external[iex].mmapping,&mapping,sizeof(mapping)); + break; + } + } + } else { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"cannot use external variable [%s] inside a crunched section!\n",dico); + } + } else { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"invalid usage of external variable [%s]\n",dico); + } + } + + return &curdicotree->dico[i]; + } + } + return NULL; +} +int DelDico(struct s_assenv *ae, char *dico, int crc) +{ + #undef FUNC + #define FUNC "DelDico" + + struct s_crcdico_tree *curdicotree; + int i,radix,dek=32; + + curdicotree=&ae->dicotree; + + while (dek) { + dek=dek-8; + radix=(crc>>dek)&0xFF; + if (curdicotree->radix[radix]) { + curdicotree=curdicotree->radix[radix]; + } else { + /* radix not found, dico is not in index */ + return 0; + } + } + for (i=0;indico;i++) { + if (strcmp(curdicotree->dico[i].name,dico)==0) { + /* must free memory */ + MemFree(curdicotree->dico[i].name); + if (indico-1) { + MemMove(&curdicotree->dico[i],&curdicotree->dico[i+1],(curdicotree->ndico-i-1)*sizeof(struct s_expr_dico)); + } + curdicotree->ndico--; + return 1; + } + } + return 0; +} + + +void InsertUsedToTree(struct s_assenv *ae, char *used, int crc) +{ + #undef FUNC + #define FUNC "InsertUsedToTree" + + struct s_crcused_tree *curusedtree; + int radix,dek=32,i; + + curusedtree=&ae->usedtree; + while (dek) { + dek=dek-8; + radix=(crc>>dek)&0xFF; + if (curusedtree->radix[radix]) { + curusedtree=curusedtree->radix[radix]; + } else { + curusedtree->radix[radix]=MemMalloc(sizeof(struct s_crcused_tree)); + curusedtree=curusedtree->radix[radix]; + memset(curusedtree,0,sizeof(struct s_crcused_tree)); + } + } + for (i=0;inused;i++) if (strcmp(used,curusedtree->used[i])==0) break; + /* no double */ + if (i==curusedtree->nused) { + FieldArrayAddDynamicValueConcat(&curusedtree->used,&curusedtree->nused,&curusedtree->mused,used); + } +} + +void FreeUsedTreeRecurse(struct s_crcused_tree *lt) +{ + #undef FUNC + #define FUNC "FreeUsedTreeRecurse" + + int i; + + for (i=0;i<256;i++) { + if (lt->radix[i]) { + FreeUsedTreeRecurse(lt->radix[i]); + } + } + if (lt->mused) { + for (i=0;inused;i++) MemFree(lt->used[i]); + MemFree(lt->used); + } + MemFree(lt); +} +void FreeUsedTree(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "FreeUsedTree" + + int i; + + for (i=0;i<256;i++) { + if (ae->usedtree.radix[i]) { + FreeUsedTreeRecurse(ae->usedtree.radix[i]); + } + } +} +int SearchUsed(struct s_assenv *ae, char *used, int crc) +{ + #undef FUNC + #define FUNC "SearchUsed" + + struct s_crcused_tree *curusedtree; + int i,radix,dek=32; + + curusedtree=&ae->usedtree; + while (dek) { + dek=dek-8; + radix=(crc>>dek)&0xFF; + if (curusedtree->radix[radix]) { + curusedtree=curusedtree->radix[radix]; + } else { + /* radix not found, used is not in index */ + return 0; + } + } + for (i=0;inused;i++) { + if (strcmp(curusedtree->used[i],used)==0) { + return 1; + } + } + return 0; +} + + + +void InsertTextToTree(struct s_assenv *ae, char *text, char *replace, int crc) +{ + #undef FUNC + #define FUNC "InsertTextToTree" + + struct s_crcstring_tree *curstringtree; + int radix,dek=32,i; + + curstringtree=&ae->stringtree; + while (dek) { + dek=dek-8; + radix=(crc>>dek)&0xFF; + if (curstringtree->radix[radix]) { + curstringtree=curstringtree->radix[radix]; + } else { + curstringtree->radix[radix]=MemMalloc(sizeof(struct s_crcused_tree)); + curstringtree=curstringtree->radix[radix]; + memset(curstringtree,0,sizeof(struct s_crcused_tree)); + } + } + for (i=0;intext;i++) if (strcmp(text,curstringtree->text[i])==0) break; + /* no double */ + if (i==curstringtree->ntext) { + text=TxtStrDup(text); + replace=TxtStrDup(replace); + FieldArrayAddDynamicValueConcat(&curstringtree->text,&curstringtree->ntext,&curstringtree->mtext,text); + FieldArrayAddDynamicValueConcat(&curstringtree->replace,&curstringtree->nreplace,&curstringtree->mreplace,replace); + } +} + +void FreeTextTreeRecurse(struct s_crcstring_tree *lt) +{ + #undef FUNC + #define FUNC "FreeTextTreeRecurse" + + int i; + + for (i=0;i<256;i++) { + if (lt->radix[i]) { + FreeTextTreeRecurse(lt->radix[i]); + } + } + if (lt->mtext) { + for (i=0;intext;i++) MemFree(lt->text[i]); + MemFree(lt->text); + } + MemFree(lt); +} +void FreeTextTree(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "FreeTextTree" + + int i; + + for (i=0;i<256;i++) { + if (ae->stringtree.radix[i]) { + FreeTextTreeRecurse(ae->stringtree.radix[i]); + } + } + if (ae->stringtree.mtext) MemFree(ae->stringtree.text); +} +int SearchText(struct s_assenv *ae, char *text, int crc) +{ + #undef FUNC + #define FUNC "SearchText" + + struct s_crcstring_tree *curstringtree; + int i,radix,dek=32; + + curstringtree=&ae->stringtree; + while (dek) { + dek=dek-8; + radix=(crc>>dek)&0xFF; + if (curstringtree->radix[radix]) { + curstringtree=curstringtree->radix[radix]; + } else { + /* radix not found, used is not in index */ + return 0; + } + } + for (i=0;intext;i++) { + if (strcmp(curstringtree->text[i],text)==0) { + return 1; + } + } + return 0; +} + + + + + + + +/* +struct s_crclabel_tree { + + + + + +struct s_crclabel_tree { + struct s_crclabel_tree *radix[256]; + struct s_label *label; + int nlabel,mlabel; +}; +*/ +void FreeLabelTreeRecurse(struct s_crclabel_tree *lt) +{ + #undef FUNC + #define FUNC "FreeLabelTreeRecurse" + + int i; + + for (i=0;i<256;i++) { + if (lt->radix[i]) { + FreeLabelTreeRecurse(lt->radix[i]); + } + } + /* label.name already freed elsewhere as this one is a copy */ + if (lt->mlabel) MemFree(lt->label); + MemFree(lt); +} +void FreeLabelTree(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "FreeLabelTree" + + int i; + + for (i=0;i<256;i++) { + if (ae->labeltree.radix[i]) { + FreeLabelTreeRecurse(ae->labeltree.radix[i]); + } + } + if (ae->labeltree.mlabel) MemFree(ae->labeltree.label); +} + +struct s_label *SearchLabel(struct s_assenv *ae, char *label, int crc) +{ + #undef FUNC + #define FUNC "SearchLabel" + + struct s_crclabel_tree *curlabeltree; + int i,radix,dek=32; + +//printf("searchLabel [%s]",label); + curlabeltree=&ae->labeltree; + while (dek) { + dek=dek-8; + radix=(crc>>dek)&0xFF; + if (curlabeltree->radix[radix]) { + curlabeltree=curlabeltree->radix[radix]; + } else { + /* radix not found, label is not in index */ +//printf(" not found\n"); + return NULL; + } + } + for (i=0;inlabel;i++) { + if (!curlabeltree->label[i].name && strcmp(ae->wl[curlabeltree->label[i].iw].w,label)==0) { + curlabeltree->label[i].used=1; +//printf(" found (global)\n"); + return &curlabeltree->label[i]; + } else if (curlabeltree->label[i].name && strcmp(curlabeltree->label[i].name,label)==0) { + curlabeltree->label[i].used=1; +//printf(" found (local or proximity)\n"); + return &curlabeltree->label[i]; + } + } + return NULL; +} + +char *MakeLocalLabel(struct s_assenv *ae,char *varbuffer, int *retdek) +{ + #undef FUNC + #define FUNC "MakeLocalLabel" + + char *locallabel; + char hexdigit[32]; + int lenbuf=0,dek,i,im; + char *zepoint; + + lenbuf=strlen(varbuffer); + + /* not so local labels */ + if (varbuffer[0]=='.') { + /* create reference */ + if (ae->lastgloballabel) { + locallabel=MemMalloc(strlen(varbuffer)+1+ae->lastgloballabellen); + sprintf(locallabel,"%s%s",ae->lastgloballabel,varbuffer); + if (retdek) *retdek=0; + return locallabel; + } else { + if (retdek) *retdek=0; + return TxtStrDup(varbuffer); + } + } + + /*************************************************** + without retdek -> build a local label + with retdek -> build the hash string + ***************************************************/ + if (!retdek) { + locallabel=MemMalloc(lenbuf+(ae->ir+ae->iw+3)*8+8); + zepoint=strchr(varbuffer,'.'); + if (zepoint) { + *zepoint=0; + } + strcpy(locallabel,varbuffer); + } else { + locallabel=MemMalloc((ae->ir+ae->iw+3)*8+4); + locallabel[0]=0; + } +//printf("locallabel=[%s] (draft)\n",locallabel); + + dek=0; + dek+=strappend(locallabel,"R"); + for (i=0;iir;i++) { + sprintf(hexdigit,"%04X",ae->repeat[i].cpt); + dek+=strappend(locallabel,hexdigit); + } + if (ae->ir) { + sprintf(hexdigit,"%04X",ae->repeat[ae->ir-1].value); + dek+=strappend(locallabel+dek,hexdigit); + } + + dek+=strappend(locallabel,"W"); + for (i=0;iiw;i++) { + sprintf(hexdigit,"%04X",ae->whilewend[i].cpt); + dek+=strappend(locallabel+dek,hexdigit); + } + if (ae->iw) { + sprintf(hexdigit,"%04X",ae->whilewend[ae->iw-1].value); + dek+=strappend(locallabel+dek,hexdigit); + } + /* where are we? */ + if (ae->imacropos) { + for (im=ae->imacropos-1;im>=0;im--) { + if (ae->idx>=ae->macropos[im].start && ae->idxmacropos[im].end) break; + } + if (im>=0) { + /* si on n'est pas dans une macro, on n'indique rien */ + sprintf(hexdigit,"M%04X",ae->macropos[im].value); + dek+=strappend(locallabel+dek,hexdigit); + } + } + if (!retdek) { + if (zepoint) { + *zepoint='.'; + strcat(locallabel+dek,zepoint); + } + } else { + *retdek=dek; + } +//printf("locallabel=[%s] (end)\n",locallabel); + return locallabel; +} + +char *TradExpression(char *zexp) +{ + #undef FUNC + #define FUNC "TradExpression" + + static char *last_expression=NULL; + char *wstr; + + if (last_expression) {MemFree(last_expression);last_expression=NULL;} + if (!zexp) return NULL; + + wstr=TxtStrDup(zexp); + wstr=TxtReplace(wstr,"[","<<",0); + wstr=TxtReplace(wstr,"]",">>",0); + wstr=TxtReplace(wstr,"m","%",0); + + last_expression=wstr; + return wstr; +} + +int TrimFloatingPointString(char *fps) { + int i=0,pflag,zflag=0; + + while (fps[i]) { + if (fps[i]=='.') { + pflag=i; + zflag=1; + } else if (fps[i]!='0') { + zflag=0; + } + i++; + } + /* truncate floating fract */ + if (zflag) { + fps[pflag]=0; + } else { + pflag=i; + } + return pflag; +} + + + +/* + translate tag or formula between curly brackets + used in label declaration + used in print directive +*/ +char *TranslateTag(struct s_assenv *ae, char *varbuffer, int *touched, int enablefast, int tagoption) { + /******************************************************* + v a r i a b l e s i n s t r i n g s + *******************************************************/ + char *starttag,*endtag,*tagcheck,*expr; + int newlen,lenw,taglen,tagidx,tagcount,validx; + char curvalstr[256]={0}; + + +//printf("TranslateTag [%s]\n",varbuffer); + + if (tagoption & E_TAGOPTION_PRESERVE) { + if (ae->iw || ae->ir) { + /* inside a loop we must care about variables */ +//printf("TranslateTag [%s] with PRESERVE inside a loop!\n",varbuffer); + return varbuffer; + } + } + + *touched=0; + while ((starttag=strchr(varbuffer+1,'{'))!=NULL) { + if ((endtag=strchr(starttag,'}'))==NULL) { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"invalid tag in string [%s]\n",varbuffer); + return NULL; + } + /* allow inception */ + tagcount=1; + tagcheck=starttag+1; + while (*tagcheck && tagcount) { + if (*tagcheck=='}') tagcount--; else if (*tagcheck=='{') tagcount++; + tagcheck++; + } + if (tagcount) { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"invalid brackets combination in string [%s]\n",varbuffer); + return NULL; + } else { + endtag=tagcheck-1; + } + *touched=1; + taglen=endtag-starttag+1; + tagidx=starttag-varbuffer; + lenw=strlen(varbuffer); // before the EOF write + *endtag=0; + /*** c o m p u t e e x p r e s s i o n ***/ + expr=TxtStrDup(starttag+1); + if (tagoption & E_TAGOPTION_REMOVESPACE) expr=TxtReplace(expr," ","",0); + if (enablefast) ExpressionFastTranslate(ae,&expr,0); + validx=(int)RoundComputeExpressionCore(ae,expr,ae->codeadr,0); + if (validx<0) { + strcpy(curvalstr,""); + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"indexed tag must NOT be a negative value [%s]\n",varbuffer); + MemFree(expr); + return NULL; + } else { + #ifdef OS_WIN + snprintf(curvalstr,sizeof(curvalstr)-1,"%d",validx); + newlen=strlen(curvalstr); + #else + newlen=snprintf(curvalstr,sizeof(curvalstr)-1,"%d",validx); + #endif + } + MemFree(expr); + if (newlen>taglen) { + /* realloc */ + varbuffer=MemRealloc(varbuffer,lenw+newlen-taglen+1); + } + if (newlen!=taglen ) { + MemMove(varbuffer+tagidx+newlen,varbuffer+tagidx+taglen,lenw-taglen-tagidx+1); + } + strncpy(varbuffer+tagidx,curvalstr,newlen); /* copy without zero terminator */ + } + + return varbuffer; +} + +#define CRC_HALT 0xD7D1BFA1 +#define CRC_NOP 0xE1830165 +#define CRC_LDI 0xE18B3F51 +#define CRC_LDD 0xE18B3F4C +#define CRC_DEC 0xE06BDD44 +#define CRC_INC 0xE19F3B52 +#define CRC_CPI 0xE077C754 +#define CRC_CPD 0xE077C74F +#define CRC_BIT 0xE073D557 +#define CRC_RES 0xE1B32D62 +#define CRC_SET 0xE1B71164 +#define CRC_CCF 0xE0742D44 +#define CRC_IND 0xE19F3B53 +#define CRC_INI 0xE19F3B58 +#define CRC_DAA 0xE068253E +#define CRC_CPL 0xE077C757 +#define CRC_EI 0x4BD5DD06 +#define CRC_DI 0x4BD5DF05 +#define CRC_IM 0x4BD5250E +#define CRC_SCF 0xE1B72D54 +#define CRC_NEG 0xE1833D52 +#define CRC_OUTI 0xEFA5F1B9 +#define CRC_OUTD 0xEFA5F1B4 +#define CRC_OUT 0xE1871170 +#define CRC_IN 0x4BD5250F + +#define CRC_RLA 0xE1B31F57 +#define CRC_RLCA 0x878DAD9A +#define CRC_RRCA 0x87A5B5A0 +#define CRC_RRA 0xE1B30B5D +#define CRC_RLD 0xE1B31F5A +#define CRC_RRD 0xE1B30B60 +#define CRC_RST 0xE1B30971 +#define CRC_RR 0x4BD5331C +#define CRC_RL 0x4BD53316 +#define CRC_RRC 0xE1B30B5F +#define CRC_RLC 0xE1B31F59 +#define CRC_SLA 0xE1B71F58 +#define CRC_SLL 0xE1B71F63 +#define CRC_SRA 0xE1B70B5E +#define CRC_SRL 0xE1B70B69 + +#define CRC_ADD 0xE07C2F41 +#define CRC_ADC 0xE07C2F40 +#define CRC_SBC 0xE1B72B50 +#define CRC_SUB 0xE1B77162 +#define CRC_XOR 0xE1DB3971 +#define CRC_AND 0xE07FDB4B +#define CRC_OR 0x4BD52919 +#define CRC_CP 0x4BD5D10B + +#define CRC_PUSH 0x97A1EDB8 +#define CRC_POP 0xE1BB1967 + +#define CRC_CALL 0x826B994 +#define CRC_JR 0x4BD52314 +#define CRC_JP 0x4BD52312 +#define CRC_DJNZ 0x37CD7BAE +#define CRC_RET 0xE1B32D63 +#define CRC_RETN 0x87E9EBB1 +#define CRC_RETI 0x87E9EBAC + +#define CRC_LD 0x4BD52F08 + +#define CRC_EX 0x4BD5DD15 +#define CRC_EXX 0xE06FF76D +#define CRC_LDIR 0xF7F59DA3 +#define CRC_LDDR 0xF7F5A79E +#define CRC_INIR 0xDFE98BAA +#define CRC_INDR 0xDFE99DA5 +#define CRC_OTIR 0xEFB9D7B6 +#define CRC_OTDR 0xEFB9A1B1 +#define CRC_CPIR 0xFF96FA6 +#define CRC_CPDR 0xFF959A1 + + + +int __GETNOP(struct s_assenv *ae,char *oplist, int didx) +{ + #undef FUNC + #define FUNC "__GETNOP" + + int idx=0,crc,tick=0; + char **opcode=NULL; + char *opref; + + /* upper case */ + while (oplist[idx]) { + oplist[idx]=toupper(oplist[idx]); + idx++; + } + /* duplicata */ + opref=TxtStrDup(oplist); + /* clean-up */ + TxtReplace(opref,"\t"," ",0); + TxtReplace(opref," "," ",1); + TxtReplace(opref,": ",":",1); + /* simplify extended registers to XL or IX */ + TxtReplace(opref,"IY","IX",0); + TxtReplace(opref,"IXL","XL",0); + TxtReplace(opref,"IXH","XL",0); + TxtReplace(opref,"LX","XL",0); + TxtReplace(opref,"HX","XL",0); + TxtReplace(opref,"LY","XL",0); + TxtReplace(opref,"HY","XL",0); + TxtReplace(opref,"YL","XL",0); + TxtReplace(opref,"XH","XL",0); + TxtReplace(opref,"YH","XL",0); + + /* count opcodes */ + opcode=TxtSplitWithChar(opref,':'); + + idx=0; + while (opcode[idx]) { + char *zeopcode,*terminator,*zearg=NULL; + char **listarg; + + zeopcode=opcode[idx]; + /* trim */ + while (*zeopcode==' ') zeopcode++; + terminator=zeopcode; + while (*terminator!=0 && *terminator!=' ') terminator++; + if (*terminator) { + zearg=terminator+1; + *terminator=0; + /* no space in args */ + TxtReplace(zearg," ","",1); + } + if (!zeopcode[0]) {idx++;continue;} + crc=GetCRC(zeopcode); + + /************************************* + * very simple and simplified parsing * + *************************************/ + switch (crc) { + case CRC_RLA: + case CRC_RLCA: + case CRC_RRCA: + case CRC_RRA: + case CRC_NOP: + case CRC_CCF: + case CRC_DAA: + case CRC_SCF: + case CRC_CPL: + case CRC_EXX: + case CRC_EI: + case CRC_DI:tick+=1;break; + + case CRC_IM: + case CRC_NEG:tick+=2;break; + + case CRC_RST: + case CRC_RETN: + case CRC_RETI: + case CRC_CPDR: + case CRC_CPIR: + case CRC_CPD: + case CRC_CPI:tick+=4;break; + + case CRC_RLD: + case CRC_RRD: + case CRC_LDD: + case CRC_LDI: + case CRC_OUTI: + case CRC_OUTD: + case CRC_LDIR: + case CRC_LDDR: + case CRC_INIR: + case CRC_INDR: + case CRC_OTIR: + case CRC_OTDR: + case CRC_IND: + case CRC_INI:tick+=5;break; + + case CRC_EX: + if (zearg) { + if (strstr(zearg,"AF") || strstr(zearg,"DE")) tick+=1; else + if (strstr(zearg,"(SP)") && strstr(zearg,"HL")) tick+=6; else + if (strstr(zearg,"(SP)") && strstr(zearg,"IX")) tick+=7; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode [%s] for GETNOP, see documentation about this directive\n",opcode[idx]); + } + break; + + case CRC_PUSH: + if (zearg) { + if (strcmp(zearg,"IX")==0) tick+=5; else tick+=4; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode [%s] for GETNOP, see documentation about this directive\n",opcode[idx]); + } + break; + + case CRC_POP: + if (zearg) { + if (strcmp(zearg,"IX")==0) tick+=4; else tick+=3; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode [%s] for GETNOP, see documentation about this directive\n",opcode[idx]); + } + break; + + case CRC_SLA: + case CRC_SLL: + case CRC_SRA: + case CRC_SRL: + case CRC_RL: + case CRC_RLC: + case CRC_RR: + case CRC_RRC: + if (zearg) { + if (strstr(zearg,"(HL)")) tick+=4; else + if (strstr(zearg,"(IX")) tick+=7; else + tick+=2; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode [%s] for GETNOP, see documentation about this directive\n",opcode[idx]); + } + break; + + case CRC_OUT: + case CRC_IN: + if (zearg) { + if (strstr(zearg,"(C)")) tick+=4; else tick+=3; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode [%s] for GETNOP, see documentation about this directive\n",opcode[idx]); + } + break; + + case CRC_ADD: + if (zearg) { + /* simplify deprecated notation */ + TxtReplace(zearg,"A,","",0); + if (strcmp(zearg,"IX,BC")==0 || strcmp(zearg,"IX,DE")==0 || strcmp(zearg,"IX,IX")==0 || strcmp(zearg,"IX,SP")==0) tick+=4; else + if (strcmp(zearg,"HL,BC")==0 || strcmp(zearg,"HL,DE")==0 || strcmp(zearg,"HL,HL")==0 || strcmp(zearg,"HL,SP")==0) tick+=3; else + if (strstr(zearg,"(HL)") || strcmp(zearg,"XL")==0) tick+=2; else + if (strstr(zearg,"(IX")) tick+=5; else + if ((*zearg>='A' && *zearg<='E') || *zearg=='H' || *zearg=='L') tick+=1; else tick+=2; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode [%s] for GETNOP, see documentation about this directive\n",opcode[idx]); + } + break; + + /* ADC/SBC/SUB/XOR/AND/OR */ + case CRC_ADC: + case CRC_SBC: + if (zearg) { + /* simplify deprecated notation */ + TxtReplace(zearg,"A,","",0); + if (strcmp(zearg,"HL,BC")==0 || strcmp(zearg,"HL,DE")==0 ||strcmp(zearg,"HL,HL")==0 ||strcmp(zearg,"HL,SP")==0) {tick+=4;break;} + } + case CRC_SUB: + /* simplify deprecated notation */ + TxtReplace(zearg,"A,","",0); + case CRC_XOR: + case CRC_AND: + case CRC_OR: + case CRC_CP: + if (zearg) { + if (strstr(zearg,"(HL)") || strcmp(zearg,"XL")==0) tick+=2; else + if (strstr(zearg,"(IX")) tick+=5; else + if ((*zearg>='A' && *zearg<='E') || *zearg=='H' || *zearg=='L') tick+=1; else tick+=2; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode [%s] for GETNOP, see documentation about this directive\n",opcode[idx]); + } + break; + + /* BIT/RES/SET */ + case CRC_BIT: + if (strstr(zearg,"(HL)")) tick+=3; else + if (strstr(zearg,"(IX")) tick+=6; else tick+=2; + break; + case CRC_RES: + case CRC_SET: + if (strstr(zearg,"(HL)")) tick+=4; else + if (strstr(zearg,"(IX")) tick+=7; else tick+=2; + break; + case CRC_DEC: + case CRC_INC: + if (strcmp(zearg,"XL")==0 || strcmp(zearg,"SP")==0 || strcmp(zearg,"BC")==0 + || strcmp(zearg,"DE")==0 || strcmp(zearg,"HL")==0) + tick+=2; + else if (strcmp(zearg,"IX")==0 || strcmp(zearg,"(HL)")==0) + tick+=3; + else if (strncmp(zearg,"(IX",3)==0) + tick+=6; + else tick++; + break; + case CRC_JP: + // JP is supposed to loop! + if (zearg) { + if (strstr(zearg,"IX")) + tick+=2; + else if (strstr(zearg,"HL")) + tick+=1; + else tick+=3; + } else tick+=3; + break; + case CRC_DJNZ: + // DJNZ is supposed to loop! + case CRC_CALL: + // CALL is supposed to skip! + case CRC_JR: + // JR is supposed to loop! + tick+=3; + break; + case CRC_RET: + // conditionnal RET shorter because it's supposed to be the exit! + if (!zearg) tick+=3; else tick+=2; + break; + + case CRC_LD: + /* big cake! */ + if (zearg && strchr(zearg,',')) { + int crc1,crc2; + + /* split args */ + listarg=TxtSplitWithChar(zearg,','); + crc1=GetCRC(listarg[0]); + crc2=GetCRC(listarg[1]); + + switch (crc1) { + case CRC_I: + case CRC_R: + switch (crc2) { + case CRC_A: + tick+=3; + break; + default: + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported LD %s,%s for GETNOP, see documentation\n",listarg[0],listarg[1]); + } + break; + case CRC_A: + case CRC_B: + case CRC_C: + case CRC_D: + case CRC_E: + case CRC_H: + case CRC_L: + switch (crc2) { + case CRC_A: + case CRC_B: + case CRC_C: + case CRC_D: + case CRC_E: + case CRC_H: + case CRC_L: + tick++; + break; + case CRC_I: + case CRC_R: + if (crc1==CRC_A) tick+=3; else + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported LD %s,%s for GETNOP, see documentation\n",listarg[0],listarg[1]); + break; + case CRC_MBC: + case CRC_MDE: + if (crc1!=CRC_A) { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported LD %s,%s for GETNOP, see documentation\n",listarg[0],listarg[1]); + break; + } + case CRC_XL: + case CRC_MHL: + tick+=2; + break; + default: + /* MIX + memory + value */ + if (strncmp(listarg[1],"(IX",3)==0) { + tick+=5; + } else if (listarg[1][0]=='(' && listarg[1][strlen(listarg[1])-1]==')') { + /* memory */ + if (crc1==CRC_A) { + tick+=4; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported LD %s,%s for GETNOP, see documentation\n",listarg[0],listarg[1]); + } + } else { + /* numeric value as default */ + tick+=2; + } + } + break; + + case CRC_XL: + switch (crc2) { + case CRC_A: + case CRC_B: + case CRC_C: + case CRC_D: + case CRC_E: + case CRC_H: + case CRC_L: + tick+=2; + break; + case CRC_XL: + tick+=2; + break; + default: + /* value */ + tick+=3; + } + break; + + case CRC_BC: + case CRC_DE: + /* memory / value */ + if (listarg[1][0]=='(' && listarg[1][strlen(listarg[1])-1]==')') tick+=6; else tick+=3; + break; + case CRC_HL: + /* memory / value */ + if (listarg[1][0]=='(' && listarg[1][strlen(listarg[1])-1]==')') tick+=5; else tick+=3; + break; + case CRC_SP: + if (crc2==CRC_HL) { + tick+=2; + } else if (crc2==CRC_IX) { + /* IX */ + tick+=3; + } else if (listarg[1][0]=='(' && listarg[1][strlen(listarg[1])-1]==')') { + /* memory */ + tick+=6; + } else tick+=3; + break; + case CRC_IX: + /* memory / value */ + if (listarg[1][0]=='(' && listarg[1][strlen(listarg[1])-1]==')') tick+=6; else tick+=4; + break; + + case CRC_MBC: + case CRC_MDE: + if (crc2==CRC_A) { + tick+=2; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported LD %s,%s for GETNOP, see documentation\n",listarg[0],listarg[1]); + } + break; + case CRC_MHL: + switch (crc2) { + case CRC_A: + case CRC_B: + case CRC_C: + case CRC_D: + case CRC_E: + case CRC_H: + case CRC_L: + tick+=2; + break; + default: + tick+=3; + break; + } + break; + default: + if (strncmp(listarg[0],"(IX",3)==0) { + /* MIX */ + switch (crc2) { + case CRC_A: + case CRC_B: + case CRC_C: + case CRC_D: + case CRC_E: + case CRC_H: + case CRC_L:tick+=5;break; + default:tick+=6; + } + } else if (listarg[0][0]=='(' && listarg[0][strlen(listarg[0])-1]==')') { + /* memory */ + switch (crc2) { + case CRC_A:tick+=4;break; + case CRC_HL:tick+=5;break; + case CRC_BC: + case CRC_DE: + case CRC_SP: + case CRC_IX:tick+=6;break; + default: + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported LD %s,%s for GETNOP, see documentation\n",listarg[0],listarg[1]); + } + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported LD %s,%s for GETNOP, see documentation\n",listarg[0],listarg[1]); + } + } + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode LD for GETNOP, need 2 arguments [%s]\n",zearg); + } + break; + + default: + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode [%s] for GETNOP, see documentation about this directive\n",opcode[idx]); + } + idx++; + } + MemFree(opref); + if (opcode) MemFree(opcode); + return tick; +} +int __GETTICK(struct s_assenv *ae,char *oplist, int didx) +{ + #undef FUNC + #define FUNC "__GETTICK" + + int idx=0,crc,tick=0; + char **opcode=NULL; + char *opref; + + /* upper case */ + while (oplist[idx]) { + oplist[idx]=toupper(oplist[idx]); + idx++; + } + /* duplicata */ + opref=TxtStrDup(oplist); + /* clean-up */ + TxtReplace(opref,"\t"," ",0); + TxtReplace(opref," "," ",1); + TxtReplace(opref,": ",":",1); + /* simplify extended registers to XL or IX */ + TxtReplace(opref,"IY","IX",0); + TxtReplace(opref,"IXL","XL",0); + TxtReplace(opref,"IXH","XL",0); + TxtReplace(opref,"LX","XL",0); + TxtReplace(opref,"HX","XL",0); + TxtReplace(opref,"LY","XL",0); + TxtReplace(opref,"HY","XL",0); + TxtReplace(opref,"YL","XL",0); + TxtReplace(opref,"XH","XL",0); + TxtReplace(opref,"YH","XL",0); + + /* count opcodes */ + opcode=TxtSplitWithChar(opref,':'); + + idx=0; + while (opcode[idx]) { + char *zeopcode,*terminator,*zearg=NULL; + char **listarg; + + zeopcode=opcode[idx]; + /* trim */ + while (*zeopcode==' ') zeopcode++; + terminator=zeopcode; + while (*terminator!=0 && *terminator!=' ') terminator++; + if (*terminator) { + zearg=terminator+1; + *terminator=0; + /* no space in args */ + TxtReplace(zearg," ","",1); + } + if (!zeopcode[0]) {idx++;continue;} + crc=GetCRC(zeopcode); + + /************************************* + * very simple and simplified parsing * + *************************************/ + switch (crc) { + case CRC_RLA: + case CRC_RLCA: + case CRC_RRCA: + case CRC_RRA: + case CRC_NOP: + case CRC_CCF: + case CRC_DAA: + case CRC_SCF: + case CRC_CPL: + case CRC_EXX: + case CRC_EI: + case CRC_DI:tick+=4;break; + + case CRC_IM: + case CRC_NEG:tick+=8;break; + + case CRC_RST:tick+=11;break; + + case CRC_RETN: + case CRC_RETI:tick+=14;break; + + case CRC_CPIR: + case CRC_CPDR: + case CRC_CPD: + case CRC_CPI: + case CRC_OUTI: + case CRC_OUTD: + case CRC_LDD: + case CRC_LDI: + case CRC_LDIR: + case CRC_LDDR: + case CRC_INIR: + case CRC_INDR: + case CRC_OTIR: + case CRC_OTDR: + case CRC_IND: + case CRC_INI:tick+=16;break; + + case CRC_RLD: + case CRC_RRD:tick+=18;break; + + case CRC_EX: + if (zearg) { + if (strstr(zearg,"AF") || strstr(zearg,"DE")) tick+=4; else + if (strstr(zearg,"(SP)") && strstr(zearg,"HL")) tick+=19; else + if (strstr(zearg,"(SP)") && strstr(zearg,"IX")) tick+=23; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode [%s] for GETTICK, see documentation about this directive\n",opcode[idx]); + } + break; + + case CRC_PUSH: + if (zearg) { + if (strcmp(zearg,"IX")==0) tick+=15; else tick+=11; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode [%s] for GETTICK, see documentation about this directive\n",opcode[idx]); + } + break; + + case CRC_POP: + if (zearg) { + if (strcmp(zearg,"IX")==0) tick+=14; else tick+=10; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode [%s] for GETTICK, see documentation about this directive\n",opcode[idx]); + } + break; + + case CRC_SLA: + case CRC_SLL: + case CRC_SRA: + case CRC_SRL: + case CRC_RL: + case CRC_RLC: + case CRC_RR: + case CRC_RRC: + if (zearg) { + if (strstr(zearg,"(HL)")) tick+=15; else + if (strstr(zearg,"(IX")) tick+=23; else + tick+=8; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode [%s] for GETTICK, see documentation about this directive\n",opcode[idx]); + } + break; + + case CRC_OUT: + if (zearg) { + if (strstr(zearg,"(C),")) tick+=12; else tick+=11; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode [%s] for GETTICK, see documentation about this directive\n",opcode[idx]); + } + break; + case CRC_IN: + if (zearg) { + if (strstr(zearg,"(C)")) tick+=12; else tick+=11; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode [%s] for GETTICK, see documentation about this directive\n",opcode[idx]); + } + break; + + case CRC_ADD: + if (zearg) { + /* simplify deprecated notation */ + TxtReplace(zearg,"A,","",0); + if (strcmp(zearg,"IX,BC")==0 || strcmp(zearg,"IX,DE")==0 || strcmp(zearg,"IX,IX")==0 || strcmp(zearg,"IX,SP")==0) tick+=15; else + if (strcmp(zearg,"HL,BC")==0 || strcmp(zearg,"HL,DE")==0 || strcmp(zearg,"HL,HL")==0 || strcmp(zearg,"HL,SP")==0) tick+=11; else + if (strstr(zearg,"(HL)")) tick+=7; else + if (strstr(zearg,"(IX")) tick+=19; else + if (strstr(zearg,"XL")) tick+=8; else + if ((*zearg>='A' && *zearg<='E') || *zearg=='H' || *zearg=='L') tick+=4; else tick+=7; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode [%s] for GETTICK, see documentation about this directive\n",opcode[idx]); + } + break; + + /* ADC/SBC/SUB/XOR/AND/OR */ + case CRC_ADC: + case CRC_SBC: + if (zearg) { + /* simplify deprecated notation */ + TxtReplace(zearg,"A,","",0); + if (strcmp(zearg,"HL,BC")==0 || strcmp(zearg,"HL,DE")==0 ||strcmp(zearg,"HL,HL")==0 ||strcmp(zearg,"HL,SP")==0) {tick+=15;break;} + } + case CRC_SUB: + if (zearg) { + /* simplify deprecated notation */ + TxtReplace(zearg,"A,","",0); + } + case CRC_XOR: + case CRC_AND: + case CRC_OR: + case CRC_CP: + if (zearg) { + if (strstr(zearg,"(HL)")) tick+=7; else + if (strstr(zearg,"(IX")) tick+=19; else + if (strstr(zearg,"XL")) tick+=8; else + if ((*zearg>='A' && *zearg<='E') || *zearg=='H' || *zearg=='L') tick+=4; else tick+=7; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode [%s] for GETTICK, see documentation about this directive\n",opcode[idx]); + } + break; + + /* BIT/RES/SET */ + case CRC_BIT: + if (strstr(zearg,"(HL)")) tick+=12; else + if (strstr(zearg,"(IX")) tick+=20; else tick+=8; + break; + case CRC_RES: + case CRC_SET: + if (strstr(zearg,"(HL)")) tick+=15; else + if (strstr(zearg,"(IX")) tick+=23; else tick+=8; + break; + case CRC_DEC: + case CRC_INC: + if (strcmp(zearg,"XL")==0) tick+=8; + else if (strcmp(zearg,"SP")==0 || strcmp(zearg,"BC")==0 || strcmp(zearg,"DE")==0 || strcmp(zearg,"HL")==0) tick+=6; + else if (strcmp(zearg,"IX")==0) tick+=10; + else if (strcmp(zearg,"(HL)")==0) tick+=11; + else if (strncmp(zearg,"(IX",3)==0) tick+=23; + else tick+=4; + break; + case CRC_JP: + // JP is supposed to loop! + if (zearg) { + if (strstr(zearg,"IX")) + tick+=8; + else if (strstr(zearg,"HL")) + tick+=4; + else tick+=10; + } else tick+=10; + break; + case CRC_DJNZ: + // DJNZ is supposed to loop! + tick+=13; + break; + case CRC_CALL: + // CALL is supposed to skip! + tick+=10; + break; + case CRC_JR: + // JR is supposed to loop! + tick+=12; + break; + case CRC_RET: + // conditionnal RET shorter because it's supposed to be the exit! + if (!zearg) tick+=10; else tick+=5; + break; + + case CRC_LD: + /* big cake! */ + if (zearg && strchr(zearg,',')) { + int crc1,crc2; + + /* split args */ + listarg=TxtSplitWithChar(zearg,','); + crc1=GetCRC(listarg[0]); + crc2=GetCRC(listarg[1]); + + switch (crc1) { + case CRC_I: + case CRC_R: + switch (crc2) { + case CRC_A: + tick+=9; + break; + default: + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported LD %s,%s for GETTICK, see documentation\n",listarg[0],listarg[1]); + } + break; + case CRC_A: + case CRC_B: + case CRC_C: + case CRC_D: + case CRC_E: + case CRC_H: + case CRC_L: + switch (crc2) { + case CRC_A: + case CRC_B: + case CRC_C: + case CRC_D: + case CRC_E: + case CRC_H: + case CRC_L: + tick+=4; + break; + case CRC_I: + case CRC_R: + if (crc1==CRC_A) tick+=9; else + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported LD %s,%s for GETTICK, see documentation\n",listarg[0],listarg[1]); + break; + case CRC_MBC: + case CRC_MDE: + if (crc1!=CRC_A) { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported LD %s,%s for GETTICK, see documentation\n",listarg[0],listarg[1]); + break; + } + case CRC_MHL: + tick+=7; + break; + case CRC_XL: + tick+=8; + break; + default: + /* MIX + memory + value */ + if (strncmp(listarg[1],"(IX",3)==0) { + tick+=19; + } else if (listarg[1][0]=='(' && listarg[1][strlen(listarg[1])-1]==')') { + /* memory */ + if (crc1==CRC_A) { + tick+=13; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported LD %s,%s for GETTICK, see documentation\n",listarg[0],listarg[1]); + } + } else { + /* numeric value as default */ + tick+=7; + } + } + break; + + case CRC_XL: + switch (crc2) { + case CRC_A: + case CRC_B: + case CRC_C: + case CRC_D: + case CRC_E: + case CRC_H: + case CRC_L: + case CRC_XL: + tick+=8; + break; + default: + /* value */ + tick+=11; + } + break; + + case CRC_BC: + case CRC_DE: + /* memory / value */ + if (listarg[1][0]=='(' && listarg[1][strlen(listarg[1])-1]==')') tick+=20; else tick+=10; + break; + case CRC_HL: + /* memory / value */ + if (listarg[1][0]=='(' && listarg[1][strlen(listarg[1])-1]==')') tick+=16; else tick+=10; + break; + case CRC_SP: + if (crc2==CRC_HL) { + tick+=6; + } else if (crc2==CRC_IX) { + /* IX */ + tick+=10; + } else if (listarg[1][0]=='(' && listarg[1][strlen(listarg[1])-1]==')') { + /* memory */ + tick+=20; + } else tick+=10; + break; + case CRC_IX: + /* memory / value */ + if (listarg[1][0]=='(' && listarg[1][strlen(listarg[1])-1]==')') tick+=20; else tick+=14; + break; + + case CRC_MBC: + case CRC_MDE: + if (crc2==CRC_A) { + tick+=7; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported LD %s,%s for GETTICK, see documentation\n",listarg[0],listarg[1]); + } + break; + case CRC_MHL: + switch (crc2) { + case CRC_A: + case CRC_B: + case CRC_C: + case CRC_D: + case CRC_E: + case CRC_H: + case CRC_L: + tick+=7; + break; + default: + tick+=10; + break; + } + break; + default: + if (strncmp(listarg[0],"(IX",3)==0) { + /* MIX */ + switch (crc2) { + case CRC_A: + case CRC_B: + case CRC_C: + case CRC_D: + case CRC_E: + case CRC_H: + case CRC_L:tick+=19;break; + default:tick+=23; + } + } else if (listarg[0][0]=='(' && listarg[0][strlen(listarg[0])-1]==')') { + /* memory */ + switch (crc2) { + case CRC_A:tick+=13;break; + case CRC_HL:tick+=16;break; + case CRC_BC: + case CRC_DE: + case CRC_SP: + case CRC_IX:tick+=20;break; + default: + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported LD %s,%s for GETTICK, see documentation\n",listarg[0],listarg[1]); + } + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported LD %s,%s for GETTICK, see documentation\n",listarg[0],listarg[1]); + } + } + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode LD for GETTICK, need 2 arguments [%s]\n",zearg); + } + break; + + default: + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode [%s] for GETTICK, see documentation about this directive\n",opcode[idx]); + } + idx++; + } + MemFree(opref); + if (opcode) MemFree(opcode); + return tick; +} +int __GETSIZE(struct s_assenv *ae,char *oplist, int didx) +{ + #undef FUNC + #define FUNC "__GETSIZE" + + int idx=0,crc,osize=0; + char **opcode=NULL; + char *opref; + + /* upper case */ + while (oplist[idx]) { + oplist[idx]=toupper(oplist[idx]); + idx++; + } + /* duplicata */ + opref=TxtStrDup(oplist); + /* clean-up */ + TxtReplace(opref,"\t"," ",0); + TxtReplace(opref," "," ",1); + TxtReplace(opref,": ",":",1); + /* simplify extended registers to XL or IX */ + TxtReplace(opref,"IY","IX",0); + TxtReplace(opref,"IXL","XL",0); + TxtReplace(opref,"IXH","XL",0); + TxtReplace(opref,"LX","XL",0); + TxtReplace(opref,"HX","XL",0); + TxtReplace(opref,"LY","XL",0); + TxtReplace(opref,"HY","XL",0); + TxtReplace(opref,"YL","XL",0); + TxtReplace(opref,"XH","XL",0); + TxtReplace(opref,"YH","XL",0); + + /* count opcodes */ + opcode=TxtSplitWithChar(opref,':'); + + idx=0; + while (opcode[idx]) { + char *zeopcode,*terminator,*zearg=NULL; + char **listarg; + + zeopcode=opcode[idx]; + /* trim */ + while (*zeopcode==' ') zeopcode++; + terminator=zeopcode; + while (*terminator!=0 && *terminator!=' ') terminator++; + if (*terminator) { + zearg=terminator+1; + *terminator=0; + /* no space in args */ + TxtReplace(zearg," ","",1); + } + if (!zeopcode[0]) {idx++;continue;} + crc=GetCRC(zeopcode); + + /************************************* + * very simple and simplified parsing * + *************************************/ + switch (crc) { + case CRC_HALT: + case CRC_RLA: + case CRC_RLCA: + case CRC_RRCA: + case CRC_RRA: + case CRC_NOP: + case CRC_CCF: + case CRC_DAA: + case CRC_SCF: + case CRC_CPL: + case CRC_EXX: + case CRC_EI: + case CRC_RST: + case CRC_RET: + case CRC_DI:osize+=1;break; + + case CRC_OUT: + case CRC_IN: + case CRC_LDD: + case CRC_LDI: + case CRC_LDIR: + case CRC_LDDR: + case CRC_CPDR: + case CRC_CPIR: + case CRC_CPD: + case CRC_CPI: + case CRC_RETN: + case CRC_RETI: + case CRC_OUTI: + case CRC_OUTD: + case CRC_INIR: + case CRC_INDR: + case CRC_OTIR: + case CRC_OTDR: + case CRC_IND: + case CRC_INI: + case CRC_RLD: + case CRC_RRD: + case CRC_IM: + case CRC_DJNZ: + case CRC_JR: + case CRC_NEG:osize+=2;break; + + case CRC_CALL:osize+=3;break; + + case CRC_EX: + if (zearg) { + if (strstr(zearg,"AF") || strstr(zearg,"DE")) osize+=1; else + if (strstr(zearg,"(SP)") && strstr(zearg,"HL")) osize+=1; else + if (strstr(zearg,"(SP)") && strstr(zearg,"IX")) osize+=2; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode [%s] for GETSIZE, see documentation about this directive\n",opcode[idx]); + } + break; + + case CRC_PUSH: + if (zearg) { + if (strcmp(zearg,"IX")==0) osize+=2; else osize+=1; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode [%s] for GETSIZE, see documentation about this directive\n",opcode[idx]); + } + break; + + case CRC_POP: + if (zearg) { + if (strcmp(zearg,"IX")==0) osize+=2; else osize+=1; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode [%s] for GETSIZE, see documentation about this directive\n",opcode[idx]); + } + break; + + case CRC_SLA: + case CRC_SLL: + case CRC_SRA: + case CRC_SRL: + case CRC_RL: + case CRC_RLC: + case CRC_RR: + case CRC_RRC: + if (zearg) { + if (strstr(zearg,"(HL)")) osize+=2; else + if (strstr(zearg,"(IX")) osize+=4; else + osize+=2; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode [%s] for GETSIZE, see documentation about this directive\n",opcode[idx]); + } + break; + + + case CRC_ADD: + if (zearg) { + /* simplify deprecated notation */ + TxtReplace(zearg,"A,","",0); + if (strcmp(zearg,"IX,")==0 || strcmp(zearg,"XL")==0) osize+=2; else + if (strstr(zearg,"(IX")) osize+=3; else + if (strstr(zearg,"HL") || (*zearg>='A' && *zearg<='E') || *zearg=='H' || *zearg=='L') osize+=1; else osize+=2; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode [%s] for GETSIZE, see documentation about this directive\n",opcode[idx]); + } + break; + + /* ADC/SBC/SUB/XOR/AND/OR */ + case CRC_ADC: + case CRC_SBC: + if (zearg) { + /* simplify deprecated notation */ + TxtReplace(zearg,"A,","",0); + if (strcmp(zearg,"HL,BC")==0 || strcmp(zearg,"HL,DE")==0 || strcmp(zearg,"HL,HL")==0 || strcmp(zearg,"HL,SP")==0) {osize+=2;break;} + } + case CRC_SUB: + /* simplify deprecated notation */ + TxtReplace(zearg,"A,","",0); + case CRC_XOR: + case CRC_AND: + case CRC_OR: + case CRC_CP: + if (zearg) { + if (strstr(zearg,"(IX")) osize+=3; else + if (strcmp(zearg,"XL")==0) osize+=2; else + if (strcmp(zearg,"(HL)")==0 || (*zearg>='A' && *zearg<='E') || *zearg=='H' || *zearg=='L') osize+=1; else osize+=2; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode [%s] for GETSIZE, see documentation about this directive\n",opcode[idx]); + } + break; + + /* BIT/RES/SET */ + case CRC_BIT: + case CRC_RES: + case CRC_SET: + if (strstr(zearg,"(IX")) osize+=4; else osize+=2; + break; + case CRC_DEC: + case CRC_INC: + if (strcmp(zearg,"(HL)")==0 || strcmp(zearg,"SP")==0 || strcmp(zearg,"BC")==0 + || strcmp(zearg,"DE")==0 || strcmp(zearg,"HL")==0) + osize+=1; + else if (strcmp(zearg,"IX")==0 || strcmp(zearg,"XL")==0) + osize+=2; + else if (strncmp(zearg,"(IX",3)==0) + osize+=3; + else osize++; + break; + case CRC_JP: + // JP is supposed to loop! + if (zearg) { + if (strstr(zearg,"IX")) + osize+=2; + else if (strstr(zearg,"HL")) + osize+=1; + else osize+=3; + } else osize+=3; + break; + + case CRC_LD: + /* big cake! */ + if (zearg && strchr(zearg,',')) { + int crc1,crc2; + + /* split args */ + listarg=TxtSplitWithChar(zearg,','); + crc1=GetCRC(listarg[0]); + crc2=GetCRC(listarg[1]); + + switch (crc1) { + case CRC_I: + case CRC_R: + switch (crc2) { + case CRC_A: + osize+=2; + break; + default: + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported LD %s,%s for GETSIZE, see documentation\n",listarg[0],listarg[1]); + } + break; + case CRC_A: + case CRC_B: + case CRC_C: + case CRC_D: + case CRC_E: + case CRC_H: + case CRC_L: + switch (crc2) { + // heading +1 + case CRC_MBC: + case CRC_MDE: + if (crc1!=CRC_A) { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported LD %s,%s for GETSIZE, see documentation\n",listarg[0],listarg[1]); + break; + } + case CRC_A: + case CRC_B: + case CRC_C: + case CRC_D: + case CRC_E: + case CRC_H: + case CRC_L: + case CRC_MHL: + osize++; + break; + case CRC_I: + case CRC_R: + if (crc1==CRC_A) osize+=2; else + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported LD %s,%s for GETSIZE, see documentation\n",listarg[0],listarg[1]); + break; + case CRC_XL: + osize+=2; + break; + default: + /* MIX + memory + value */ + if (strncmp(listarg[1],"(IX",3)==0) { + osize+=3; + } else if (listarg[1][0]=='(' && listarg[1][strlen(listarg[1])-1]==')') { + /* absolute memory address */ + if (crc1==CRC_A) { + osize+=3; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported LD %s,%s for GETSIZE, see documentation\n",listarg[0],listarg[1]); + } + } else { + /* numeric value as default */ + osize+=2; + } + } + break; + + case CRC_XL: + switch (crc2) { + case CRC_A: + case CRC_B: + case CRC_C: + case CRC_D: + case CRC_E: + case CRC_H: + case CRC_L://legal??? + case CRC_XL: + osize+=2; + break; + default: + /* value */ + osize+=3; + } + break; + + case CRC_BC: + case CRC_DE: + /* memory / value */ + if (listarg[1][0]=='(' && listarg[1][strlen(listarg[1])-1]==')') osize+=4; else osize+=3; + break; + case CRC_HL: + /* memory / value */ + osize+=3; + break; + case CRC_SP: + if (crc2==CRC_HL) { + osize+=1; + } else if (crc2==CRC_IX) { + /* IX */ + osize+=2; + } else if (listarg[1][0]=='(' && listarg[1][strlen(listarg[1])-1]==')') { + /* memory */ + osize+=4; + } else osize+=3; /* value */ + break; + case CRC_IX: + /* memory / value */ + osize+=4; + break; + + case CRC_MBC: + case CRC_MDE: + if (crc2==CRC_A) { + osize+=1; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported LD %s,%s for GETSIZE, see documentation\n",listarg[0],listarg[1]); + } + break; + case CRC_MHL: + switch (crc2) { + case CRC_A: + case CRC_B: + case CRC_C: + case CRC_D: + case CRC_E: + case CRC_H: + case CRC_L: + osize+=1; + break; + default: + osize+=2; /* value */ + break; + } + break; + default: + if (strncmp(listarg[0],"(IX",3)==0) { + /* MIX */ + switch (crc2) { + case CRC_A: + case CRC_B: + case CRC_C: + case CRC_D: + case CRC_E: + case CRC_H: + case CRC_L:osize+=3;break; + default:osize+=4; /* value */ + } + } else if (listarg[0][0]=='(' && listarg[0][strlen(listarg[0])-1]==')') { + /* memory */ + switch (crc2) { + case CRC_A: + case CRC_HL:osize+=3;break; + case CRC_BC: + case CRC_DE: + case CRC_SP: + case CRC_IX:osize+=4;break; + default: + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported LD %s,%s for GETSIZE, see documentation\n",listarg[0],listarg[1]); + } + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported LD %s,%s for GETSIZE, see documentation\n",listarg[0],listarg[1]); + } + } + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode LD for GETSIZE, need 2 arguments [%s]\n",zearg); + } + break; + + default: + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"unsupported opcode [%s] for GETSIZE, see documentation about this directive\n",opcode[idx]); + } + idx++; + } + MemFree(opref); + if (opcode) MemFree(opcode); + return osize; +} +/* + default returned value of Duration is NOP + but BUILDZX usage change this to ticks! +*/ +int __DURATION(struct s_assenv *ae,char *opcode, int didx) +{ + #undef FUNC + #define FUNC "__DURATION" + + if (!ae->forcezx) return __GETNOP(ae,opcode,didx); + return __GETTICK(ae,opcode,didx); +} +int __FILESIZE(struct s_assenv *ae,char *zefile, int didx) +{ + #undef FUNC + #define FUNC "__DURATION" + + FILE *f; + int zesize; + + f=fopen(zefile,"rb"); + if (!f) { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"cannot retrieve filesize of [%s] file\n",zefile); + return 0; + } + fseek(f,0,SEEK_END); + zesize=ftell(f); + fclose(f); + return zesize; +} + +int __Soft2HardInk(struct s_assenv *ae,int soft, int didx) { + switch (soft) { + case 0:return 64+20;break; + case 1:return 64+4 ;break; + case 2:return 64+21 ;break; + case 3:return 64+28 ;break; + case 4:return 64+24 ;break; + case 5:return 64+29 ;break; + case 6:return 64+12 ;break; + case 7:return 64+5 ;break; + case 8:return 64+13 ;break; + case 9:return 64+22 ;break; + case 10:return 64+6 ;break; + case 11:return 64+23 ;break; + case 12:return 64+30 ;break; + case 13:return 64+0 ;break; + case 14:return 64+31 ;break; + case 15:return 64+14 ;break; + case 16:return 64+7 ;break; + case 17:return 64+15 ;break; + case 18:return 64+18 ;break; + case 19:return 64+2 ;break; + case 20:return 64+19 ;break; + case 21:return 64+26 ;break; + case 22:return 64+25 ;break; + case 23:return 64+27 ;break; + case 24:return 64+10 ;break; + case 25:return 64+3 ;break; + case 26:return 64+11 ;break; + default: + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"SOFT2HARD_INK needs 0-26 color index"); + } + return 0; +} +int __Hard2SoftInk(struct s_assenv *ae,int hard, int didx) { + hard&=31; + switch (hard) { + case 0:return 13;break; + case 1:return 13;break; + case 2:return 19;break; + case 3:return 25;break; + case 4:return 1;break; + case 5:return 7;break; + case 6:return 10;break; + case 7:return 16;break; + case 8:return 7;break; + case 9:return 25;break; + case 10:return 24;break; + case 11:return 26;break; + case 12:return 6;break; + case 13:return 8;break; + case 14:return 15;break; + case 15:return 17;break; + case 16:return 1;break; + case 17:return 19;break; + case 18:return 18;break; + case 19:return 20;break; + case 20:return 0;break; + case 21:return 2;break; + case 22:return 9;break; + case 23:return 11;break; + case 24:return 4;break; + case 25:return 22;break; + case 26:return 21;break; + case 27:return 23;break; + case 28:return 3;break; + case 29:return 5;break; + case 30:return 12;break; + case 31:return 14;break; + default:/*warning remover*/ + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"SOFT2HARD_INK warning remover"); + } + return 0; +} + +double ComputeExpressionCore(struct s_assenv *ae,char *original_zeexpression,int ptr, int didx) +{ + #undef FUNC + #define FUNC "ComputeExpressionCore" + + /* static execution buffers */ + static double *accu=NULL; + static int maccu=0; + static struct s_compute_element *computestack=NULL; + static int maxcomputestack=0; + int i,j,paccu=0; + int nbtokenstack=0; + int nbcomputestack=0; + int nboperatorstack=0; + + struct s_compute_element stackelement; + int o2,okclose,itoken; + + int idx=0,crc,icheck,is_binary,ivar=0; + char asciivalue[11]; + unsigned char c; + int accu_err=0; + /* backup alias replace */ + char *zeexpression,*expr; + int original=1; + int ialias,startvar=0; + int newlen,lenw; + /* dictionnary */ + struct s_expr_dico *curdic; + struct s_label *curlabel; + int minusptr,imkey,bank,page; + double curval; + int is_string=0; + /* negative value */ + int allow_minus_as_sign=0; + /* extended replace in labels */ + int curly=0,curlyflag=0; + char *Automate; + double dummint; + + /* memory cleanup */ + if (!ae) { + if (maccu) MemFree(accu); + accu=NULL;maccu=0; + if (maxcomputestack) MemFree(computestack); + computestack=NULL;maxcomputestack=0; + return 0.0; + } + + /* be sure to have at least some bytes allocated */ + StateMachineResizeBuffer(&ae->computectx->varbuffer,128,&ae->computectx->maxivar); + + +#if TRACE_COMPUTE_EXPRESSION + printf("expression=[%s]\n",original_zeexpression); +#endif + zeexpression=original_zeexpression; + if (!zeexpression[0]) { + return 0; + } + /* double hack if the first value is negative */ + if (zeexpression[0]=='-') { + if (ae->AutomateExpressionValidCharFirst[(int)zeexpression[1]&0xFF]) { + allow_minus_as_sign=1; + } else { + memset(&stackelement,0,sizeof(stackelement)); + ObjectArrayAddDynamicValueConcat((void **)&ae->computectx->tokenstack,&nbtokenstack,&ae->computectx->maxtokenstack,&stackelement,sizeof(stackelement)); + } + } + + /* is there ascii char? */ + while ((c=zeexpression[idx])!=0) { + if (c=='\'' || c=='"') { + /* echappement */ + if (zeexpression[idx+1]=='\\') { + if (zeexpression[idx+2] && zeexpression[idx+3]==c) { + sprintf(asciivalue,"#%03X",zeexpression[idx+2]); + memcpy(zeexpression+idx,asciivalue,4); + idx+=3; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Only single escaped char may be quoted [%s]\n",TradExpression(zeexpression)); + zeexpression[0]=0; + return 0; + } + } else if (zeexpression[idx+1] && zeexpression[idx+2]==c) { + sprintf(asciivalue,"#%02X",zeexpression[idx+1]); + memcpy(zeexpression+idx,asciivalue,3); + idx+=2; + } else { + //printf("Expression with => moar than one char in quotes\n"); + //MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Only single char may be quoted [%s]\n",TradExpression(zeexpression)); + //zeexpression[0]=0; + //return 0; + idx++; + while (zeexpression[idx] && zeexpression[idx]!=c) idx++; // no escape code management + + } + } + + idx++; + } +#if TRACE_COMPUTE_EXPRESSION + printf("apres conversion des chars [%s]\n",zeexpression); +#endif + /*********************************************************** + P A T C H F O R P O S I T I V E V A L U E + ***********************************************************/ + if (zeexpression[0]=='+') idx=1; else idx=0; + /*********************************************************** + C O M P U T E E X P R E S S I O N M A I N L O O P + ***********************************************************/ + while ((c=zeexpression[idx])!=0) { + switch (c) { + case '"': + case '\'': + //printf("COMPUTE => string detected!\n"); + ivar=0; + idx++; + while (zeexpression[idx] && zeexpression[idx]!=c) { + ae->computectx->varbuffer[ivar++]=zeexpression[idx]; + StateMachineResizeBuffer(&ae->computectx->varbuffer,ivar,&ae->computectx->maxivar); + idx++; + } + if (zeexpression[idx]) idx++; else MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"ComputeExpression [%s] quote bug!\n",TradExpression(zeexpression)); + ae->computectx->varbuffer[ivar]=0; + is_string=1; // donc on ira jamais utiliser startvar derriere + break; + + /* parenthesis */ + case ')': + /* next to a closing parenthesis, a minus is an operator */ + allow_minus_as_sign=0; + break; + case '(': + /* operator detection */ + case '*': + case '/': + case '^': + case '[': + case 'm': + case '+': + case ']': + allow_minus_as_sign=1; + break; + case '&': + allow_minus_as_sign=1; + if (c=='&' && zeexpression[idx+1]=='&') { + idx++; + c='a'; // boolean AND + } + break; + case '|': + allow_minus_as_sign=1; + if (c=='|' && zeexpression[idx+1]=='|') { + idx++; + c='o'; // boolean OR + } + break; + /* testing */ + case '<': + allow_minus_as_sign=1; + if (zeexpression[idx+1]=='=') { + idx++; + c='k'; // boolean LOWEREQ + } else if (zeexpression[idx+1]=='>') { + idx++; + c='n'; // boolean NOTEQUAL + } else { + c='l'; + } + break; + case '>': + allow_minus_as_sign=1; + if (zeexpression[idx+1]=='=') { + idx++; + c='h'; // boolean GREATEREQ + } else { + c='g'; + } + break; + case '!': + allow_minus_as_sign=1; + if (zeexpression[idx+1]=='=') { + idx++; + c='n'; // boolean NOTEQUAL + } else { + c='b'; + } + break; + case '=': + allow_minus_as_sign=1; + /* expecting == */ + if (zeexpression[idx+1]=='=') { + idx++; + c='e'; // boolean EQUAL + /* except in maxam mode with a single = */ + } else if (ae->maxam) { + c='e'; // boolean EQUAL + /* cannot affect data inside an expression */ + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] cannot set variable inside an expression\n",TradExpression(zeexpression)); + return 0; + } + break; + case '-': + if (allow_minus_as_sign) { + /* previous char was an opening parenthesis or an operator */ + ivar=0; + ae->computectx->varbuffer[ivar++]='-'; + StateMachineResizeBuffer(&ae->computectx->varbuffer,ivar,&ae->computectx->maxivar); + c=zeexpression[++idx]; + if (ae->AutomateExpressionValidCharFirst[(int)c&0xFF]) { + ae->computectx->varbuffer[ivar++]=c; + StateMachineResizeBuffer(&ae->computectx->varbuffer,ivar,&ae->computectx->maxivar); + c=zeexpression[++idx]; + while (ae->AutomateExpressionValidChar[(int)c&0xFF]) { + ae->computectx->varbuffer[ivar++]=c; + StateMachineResizeBuffer(&ae->computectx->varbuffer,ivar,&ae->computectx->maxivar); + c=zeexpression[++idx]; + } + } + ae->computectx->varbuffer[ivar]=0; + if (ivar<2) { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] invalid minus sign\n",TradExpression(zeexpression)); + if (!original) { + MemFree(zeexpression); + } + return 0; + } + break; + } + allow_minus_as_sign=1; + break; + + /* operator OR binary value */ + case '%': + /* % symbol may be a modulo or a binary literal value */ + is_binary=0; + for (icheck=1;zeexpression[idx+icheck];icheck++) { + switch (zeexpression[idx+icheck]) { + case '1': + case '0':/* still binary */ + is_binary=1; + break; + case '+': + case '-': + case '/': + case '*': + case '|': + case 'm': + case '%': + case '^': + case '&': + case '(': + case ')': + case '=': + case '<': + case '>': + case '!': + case '[': + case ']': + if (is_binary) is_binary=2; else is_binary=-1; + break; + default: + is_binary=-1; + } + if (is_binary==2) { + break; + } + if (is_binary==-1) { + is_binary=0; + break; + } + } + if (!is_binary) { + allow_minus_as_sign=1; + c='m'; + break; + } + default: + allow_minus_as_sign=0; + /* semantic analysis */ + startvar=idx; + ivar=0; + /* first char does not allow same chars as next chars */ + if (ae->AutomateExpressionValidCharFirst[((int)c)&0xFF]) { + ae->computectx->varbuffer[ivar++]=c; + if (c=='{') { + /* not a formula but only a prefix tag */ + curly++; + } + StateMachineResizeBuffer(&ae->computectx->varbuffer,ivar,&ae->computectx->maxivar); + idx++; + c=zeexpression[idx]; + Automate=ae->AutomateExpressionValidChar; + while (Automate[((int)c)&0xFF]) { + if (c=='{') { + curly++; + curlyflag=1; + Automate=ae->AutomateExpressionValidCharExtended; + } else if (c=='}') { + curly--; + if (!curly) { + Automate=ae->AutomateExpressionValidChar; + } + } + ae->computectx->varbuffer[ivar++]=c; + StateMachineResizeBuffer(&ae->computectx->varbuffer,ivar,&ae->computectx->maxivar); + idx++; + c=zeexpression[idx]; + } + } + ae->computectx->varbuffer[ivar]=0; + if (!ivar) { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"ComputeExpression invalid char (%d=%c) expression [%s]\n",c,c>31?c:' ',TradExpression(zeexpression)); + if (!original) { + MemFree(zeexpression); + } + return 0; + } else if (curly) { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"ComputeExpression wrong curly brackets in expression [%s]\n",TradExpression(zeexpression)); + if (!original) { + MemFree(zeexpression); + } + return 0; + } + } + if (c && !ivar) idx++; + + /************************************ + S T A C K D I S P A T C H E R + ************************************/ + /* push operator or stack value */ + if (!ivar) { +#if TRACE_COMPUTE_EXPRESSION + printf("pushoperator [%c]\n",c); +#endif + /************************************ + O P E R A T O R + ************************************/ + stackelement=ae->AutomateElement[c]; + if (stackelement.operator>E_COMPUTE_OPERATION_GREATEREQ) { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] has unknown operator %c (%d)\n",TradExpression(zeexpression),c>31?c:'.',c); + } + /* stackelement.value isn't used */ + stackelement.string=NULL; + } else if (is_string) { +#if TRACE_COMPUTE_EXPRESSION + printf("pushstring [%s]\n",ae->computectx->varbuffer); +#endif + stackelement.operator=E_COMPUTE_OPERATION_PUSH_DATASTC; + /* priority & value isn't used */ + stackelement.string=TxtStrDup(ae->computectx->varbuffer); + allow_minus_as_sign=0; + ivar=is_string=0; + } else { + /************************************ + V A L U E + ************************************/ +#if TRACE_COMPUTE_EXPRESSION + printf("value [%s]\n",ae->computectx->varbuffer); +#endif + if (ae->computectx->varbuffer[0]=='-') minusptr=1; else minusptr=0; + /* constantes ou variables/labels */ + switch (ae->computectx->varbuffer[minusptr]) { + case '0': + /* 0x hexa value hack */ + if (ae->computectx->varbuffer[minusptr+1]=='X' && ae->AutomateHexa[(int)ae->computectx->varbuffer[minusptr+2]&0xFF]) { + for (icheck=minusptr+3;ae->computectx->varbuffer[icheck];icheck++) { + if (ae->AutomateHexa[(int)ae->computectx->varbuffer[icheck]&0xFF]) continue; + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid hex number\n",TradExpression(zeexpression),ae->computectx->varbuffer); + break; + } + curval=strtol(ae->computectx->varbuffer+minusptr+2,NULL,16); + break; + } else + /* 0b binary value hack */ + if (ae->computectx->varbuffer[minusptr+1]=='B' && (ae->computectx->varbuffer[minusptr+2]>='0' && ae->computectx->varbuffer[minusptr+2]<='1')) { + for (icheck=minusptr+3;ae->computectx->varbuffer[icheck];icheck++) { + if (ae->computectx->varbuffer[icheck]>='0' && ae->computectx->varbuffer[icheck]<='1') continue; + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid binary number\n",TradExpression(zeexpression),ae->computectx->varbuffer); + break; + } + curval=strtol(ae->computectx->varbuffer+minusptr+2,NULL,2); + break; + } + /* 0o octal value hack */ + if (ae->computectx->varbuffer[minusptr+1]=='O' && (ae->computectx->varbuffer[minusptr+2]>='0' && ae->computectx->varbuffer[minusptr+2]<='5')) { + for (icheck=minusptr+3;ae->computectx->varbuffer[icheck];icheck++) { + if (ae->computectx->varbuffer[icheck]>='0' && ae->computectx->varbuffer[icheck]<='5') continue; + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid octal number\n",TradExpression(zeexpression),ae->computectx->varbuffer); + break; + } + curval=strtol(ae->computectx->varbuffer+minusptr+2,NULL,2); + break; + } + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* check number */ + for (icheck=minusptr;ae->computectx->varbuffer[icheck];icheck++) { + if (ae->AutomateDigit[(int)ae->computectx->varbuffer[icheck]&0xFF]) continue; + /* Intel hexa & binary style */ + switch (ae->computectx->varbuffer[strlen(ae->computectx->varbuffer)-1]) { + case 'H': + for (icheck=minusptr;ae->computectx->varbuffer[icheck+1];icheck++) { + if (ae->AutomateHexa[(int)ae->computectx->varbuffer[icheck]&0xFF]) continue; + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid hex number\n",TradExpression(zeexpression),ae->computectx->varbuffer); + } + curval=strtol(ae->computectx->varbuffer+minusptr,NULL,16); + break; + case 'B': + for (icheck=minusptr;ae->computectx->varbuffer[icheck+1];icheck++) { + if (ae->computectx->varbuffer[icheck]=='0' || ae->computectx->varbuffer[icheck]=='1') continue; + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid binary number\n",TradExpression(zeexpression),ae->computectx->varbuffer); + } + curval=strtol(ae->computectx->varbuffer+minusptr,NULL,2); + break; + default: + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid number\n",TradExpression(zeexpression),ae->computectx->varbuffer); + } + icheck=0; + break; + } + if (!ae->computectx->varbuffer[icheck]) curval=atof(ae->computectx->varbuffer+minusptr); + break; + case '%': + /* check number */ + if (!ae->computectx->varbuffer[minusptr+1]) { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is an empty binary number\n",TradExpression(zeexpression),ae->computectx->varbuffer); + } + for (icheck=minusptr+1;ae->computectx->varbuffer[icheck];icheck++) { + if (ae->computectx->varbuffer[icheck]=='0' || ae->computectx->varbuffer[icheck]=='1') continue; + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid binary number\n",TradExpression(zeexpression),ae->computectx->varbuffer); + break; + } + curval=strtol(ae->computectx->varbuffer+minusptr+1,NULL,2); + break; + case '#': + /* check number */ + if (!ae->computectx->varbuffer[minusptr+1]) { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is an empty hex number\n",TradExpression(zeexpression),ae->computectx->varbuffer); + } + for (icheck=minusptr+1;ae->computectx->varbuffer[icheck];icheck++) { + if (ae->AutomateHexa[(int)ae->computectx->varbuffer[icheck]&0xFF]) continue; + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid hex number\n",TradExpression(zeexpression),ae->computectx->varbuffer); + break; + } + curval=strtol(ae->computectx->varbuffer+minusptr+1,NULL,16); + break; + default: + if (1 || !curlyflag) { + /* $ hex value hack */ + if (ae->computectx->varbuffer[minusptr+0]=='$' && ae->AutomateHexa[(int)ae->computectx->varbuffer[minusptr+1]&0xFF]) { + for (icheck=minusptr+2;ae->computectx->varbuffer[icheck];icheck++) { + if (ae->AutomateHexa[(int)ae->computectx->varbuffer[icheck]&0xFF]) continue; + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid hex number\n",TradExpression(zeexpression),ae->computectx->varbuffer); + break; + } + curval=strtol(ae->computectx->varbuffer+minusptr+1,NULL,16); + break; + } + /* @ octal value hack */ + if (ae->computectx->varbuffer[minusptr+0]=='@' && ((ae->computectx->varbuffer[minusptr+1]>='0' && ae->computectx->varbuffer[minusptr+1]<='7'))) { + for (icheck=minusptr+2;ae->computectx->varbuffer[icheck];icheck++) { + if (ae->computectx->varbuffer[icheck]>='0' && ae->computectx->varbuffer[icheck]<='7') continue; + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid octal number\n",TradExpression(zeexpression),ae->computectx->varbuffer); + break; + } + curval=strtol(ae->computectx->varbuffer+minusptr+1,NULL,8); + break; + } + /* Intel hexa value hack */ + if (ae->AutomateHexa[(int)ae->computectx->varbuffer[minusptr+0]&0xFF]) { + if (ae->computectx->varbuffer[strlen(ae->computectx->varbuffer)-1]=='H') { + for (icheck=minusptr;ae->computectx->varbuffer[icheck+1];icheck++) { + if (!ae->AutomateHexa[(int)ae->computectx->varbuffer[icheck]&0xFF]) break; + } + if (!ae->computectx->varbuffer[icheck+1]) { + curval=strtol(ae->computectx->varbuffer+minusptr,NULL,16); + break; + } + } + } + } + + + if (curlyflag) { + char *minivarbuffer; + int touched; + + /* besoin d'un sous-contexte */ + minivarbuffer=TxtStrDup(ae->computectx->varbuffer+minusptr); + ae->computectx=&ae->ctx2; +#if TRACE_COMPUTE_EXPRESSION + printf("curly [%s]\n",minivarbuffer); +#endif + minivarbuffer=TranslateTag(ae,minivarbuffer, &touched,0,E_TAGOPTION_NONE); +#if TRACE_COMPUTE_EXPRESSION + printf("après curly [%s]\n",minivarbuffer); +#endif + ae->computectx=&ae->ctx1; + if (!touched) { + strcpy(ae->computectx->varbuffer+minusptr,minivarbuffer); + } else { + StateMachineResizeBuffer(&ae->computectx->varbuffer,strlen(minivarbuffer)+2,&ae->computectx->maxivar); + strcpy(ae->computectx->varbuffer+minusptr,minivarbuffer); + } + MemFree(minivarbuffer); + curlyflag=0; + } + + crc=GetCRC(ae->computectx->varbuffer+minusptr); + /*************************************************** + L O O K I N G F O R A F U N C T I O N + ***************************************************/ + for (imkey=0;math_keyword[imkey].mnemo[0];imkey++) { + if (crc==math_keyword[imkey].crc && strcmp(ae->computectx->varbuffer+minusptr,math_keyword[imkey].mnemo)==0) { + if (c=='(') { + /* push function as operator! */ + stackelement.operator=math_keyword[imkey].operation; + stackelement.string=NULL; + /************************************************ + C R E A T E E X T R A T O K E N + ************************************************/ + ObjectArrayAddDynamicValueConcat((void **)&ae->computectx->tokenstack,&nbtokenstack,&ae->computectx->maxtokenstack,&stackelement,sizeof(stackelement)); + stackelement.operator=E_COMPUTE_OPERATION_OPEN; + ObjectArrayAddDynamicValueConcat((void **)&ae->computectx->tokenstack,&nbtokenstack,&ae->computectx->maxtokenstack,&stackelement,sizeof(stackelement)); + allow_minus_as_sign=1; + idx++; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is a reserved keyword!\n",TradExpression(zeexpression),math_keyword[imkey].mnemo); + curval=0; + idx++; + } + ivar=0; + break; + } + } + if (math_keyword[imkey].mnemo[0]) continue; + + if (ae->computectx->varbuffer[minusptr+0]=='$' && ae->computectx->varbuffer[minusptr+1]==0) { + curval=ptr; + } else { +#if TRACE_COMPUTE_EXPRESSION + printf("search dico [%s]\n",ae->computectx->varbuffer+minusptr); +#endif + curdic=SearchDico(ae,ae->computectx->varbuffer+minusptr,crc); + if (curdic) { +#if TRACE_COMPUTE_EXPRESSION + printf("trouvé valeur=%.2lf\n",curdic->v); +#endif + curval=curdic->v; + break; + } else { + /* getbank hack */ + if (ae->computectx->varbuffer[minusptr]!='{') { + bank=0; + page=0; + } else if (strncmp(ae->computectx->varbuffer+minusptr,"{BANK}",6)==0) { + bank=6; + page=0; + /* obligé de recalculer le CRC */ + crc=GetCRC(ae->computectx->varbuffer+minusptr+bank); + } else if (strncmp(ae->computectx->varbuffer+minusptr,"{PAGE}",6)==0) { + bank=6; + page=1; + /* obligé de recalculer le CRC */ + crc=GetCRC(ae->computectx->varbuffer+minusptr+bank); + } else if (strncmp(ae->computectx->varbuffer+minusptr,"{PAGESET}",9)==0) { + bank=9; + page=2; + /* obligé de recalculer le CRC */ + crc=GetCRC(ae->computectx->varbuffer+minusptr+bank); + } else if (strncmp(ae->computectx->varbuffer+minusptr,"{SIZEOF}",8)==0) { + bank=8; + page=3; + /* obligé de recalculer le CRC */ + crc=GetCRC(ae->computectx->varbuffer+minusptr+bank); + /* search in structures prototypes and subfields */ + for (i=0;iirasmstruct;i++) { + if (ae->rasmstruct[i].crc==crc && strcmp(ae->rasmstruct[i].name,ae->computectx->varbuffer+minusptr+bank)==0) { + curval=ae->rasmstruct[i].size; + break; + } + + for (j=0;jrasmstruct[i].irasmstructfield;j++) { + if (ae->rasmstruct[i].rasmstructfield[j].crc==crc && strcmp(ae->rasmstruct[i].rasmstructfield[j].fullname,ae->computectx->varbuffer+minusptr+bank)==0) { + curval=ae->rasmstruct[i].rasmstructfield[j].size; + i=ae->irasmstruct+1; + break; + } + } + } + + if (i==ae->irasmstruct) { + /* search in structures aliases */ + for (i=0;iirasmstructalias;i++) { + if (ae->rasmstructalias[i].crc==crc && strcmp(ae->rasmstructalias[i].name,ae->computectx->varbuffer+minusptr+bank)==0) { + curval=ae->rasmstructalias[i].size+ae->rasmstructalias[i].ptr; + break; + } + } + if (i==ae->irasmstructalias) { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"cannot SIZEOF unknown structure [%s]!\n",ae->computectx->varbuffer+minusptr+bank); + curval=0; + } + } + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is an unknown prefix!\n",TradExpression(zeexpression),ae->computectx->varbuffer); + bank=0; // on pourrait sauter le tag pour eviter la merde a suivre + page=0; + } + /* limited label translation while processing crunched blocks + ae->curlz == current crunched block processed + expression->crunch_block=0 -> oui + expression->crunch_block=1 -> oui si même block + expression->crunch_block=2 -> non car sera relogée + */ + if (page!=3) { + + + +if (didx>0 && didxie) { + if (ae->expression[didx].module) { + char *dblvarbuffer; +#if TRACE_LABEL || TRACE_COMPUTE_EXPRESSION + printf("search label [%s] in an expression / module=[%s]\n",ae->computectx->varbuffer+minusptr+bank,ae->expression[didx].module); +#endif + dblvarbuffer=MemMalloc(strlen(ae->computectx->varbuffer)+strlen(ae->expression[didx].module)+2); + + strcpy(dblvarbuffer,ae->expression[didx].module); + strcat(dblvarbuffer,ae->module_separator); + strcat(dblvarbuffer,ae->computectx->varbuffer+minusptr+bank); + + /* always try to find label from current module */ + curlabel=SearchLabel(ae,dblvarbuffer,GetCRC(dblvarbuffer)); + MemFree(dblvarbuffer); + } else { +#if TRACE_LABEL || TRACE_COMPUTE_EXPRESSION + printf("search label [%s] in an expression without module\n",ae->computectx->varbuffer+minusptr+bank); +#endif + curlabel=NULL; + } + + /* pas trouvé on cherche LEGACY */ + if (!curlabel) { + curlabel=SearchLabel(ae,ae->computectx->varbuffer+minusptr+bank,crc); +#if TRACE_LABEL || TRACE_COMPUTE_EXPRESSION + if (curlabel) printf("label LEGACY trouve! ptr=%d\n",curlabel->ptr); else printf("label non trouve!\n"); +#endif + } +#if TRACE_LABEL || TRACE_COMPUTE_EXPRESSION + else printf("label trouve via ajout du MODULE\n"); +#endif + +} else { +#if TRACE_LABEL || TRACE_COMPUTE_EXPRESSION + printf("search label [%s] outside an expression taking current module!\n",ae->computectx->varbuffer+minusptr+bank); +#endif + if (ae->module) { + char *dblvarbuffer; + dblvarbuffer=MemMalloc(strlen(ae->computectx->varbuffer)+strlen(ae->module)+2); + strcpy(dblvarbuffer,ae->module); + strcat(dblvarbuffer,ae->module_separator); + strcat(dblvarbuffer,ae->computectx->varbuffer+minusptr+bank); + + /* on essaie toujours de trouver le label du module courant */ + curlabel=SearchLabel(ae,dblvarbuffer,GetCRC(dblvarbuffer)); + /* pas trouvé on cherche LEGACY */ + if (!curlabel) curlabel=SearchLabel(ae,ae->computectx->varbuffer+minusptr+bank,crc); +#if TRACE_LABEL || TRACE_COMPUTE_EXPRESSION + else printf("label trouve via ajout du MODULE\n"); +#endif + + MemFree(dblvarbuffer); + } else { + curlabel=SearchLabel(ae,ae->computectx->varbuffer+minusptr+bank,crc); + } +} + + + + if (curlabel) { + if (ae->stage<2) { + if (curlabel->lz==-1) { + if (!bank) { + curval=curlabel->ptr; + } else { +#if TRACE_COMPUTE_EXPRESSION +printf("page=%d | ptr=%X ibank=%d\n",page,curlabel->ptr,curlabel->ibank); +#endif + switch (page) { + case 2: /* PAGESET */ + if (curlabel->ibanksetgate[curlabel->ibank]; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] cannot use PAGESET - label [%s] is in a temporary space!\n",TradExpression(zeexpression),ae->computectx->varbuffer); + curval=curlabel->ibank; + } + break; + case 1:/* PAGE */ + if (curlabel->ibankbankset[curlabel->ibank>>2]) { + curval=ae->bankgate[(curlabel->ibank&0x1FC)+(curlabel->ptr>>14)]; + } else { + curval=ae->bankgate[curlabel->ibank]; + } + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] cannot use PAGE - label [%s] is in a temporary space!\n",TradExpression(zeexpression),ae->computectx->varbuffer); + curval=curlabel->ibank; + } + break; + case 0: + curval=curlabel->ibank; + break; + default:MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INTERNAL ERROR (unknown paging)\n",GetExpFile(ae,didx),GetExpLine(ae,didx));FreeAssenv(ae);exit(-664); + } + } + } else { + /* label MUST be intermediate OR in the crunched block */ + if (ae->lzsection[curlabel->lz].lzversion==0 || (curlabel->iorgzone==ae->expression[didx].iorgzone && curlabel->ibank==ae->expression[didx].ibank && curlabel->lz<=ae->expression[didx].lz)) { + if (!bank) { + curval=curlabel->ptr; + } else { + if (page) { + switch (page) { + case 2: /* PAGESET */ + if (curlabel->ibanksetgate[curlabel->ibank]; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] cannot use PAGESET - label [%s] is in a temporary space!\n",TradExpression(zeexpression),ae->computectx->varbuffer); + curval=curlabel->ibank; + } + break; + case 1: /* PAGE */ + if (curlabel->ibankbankset[curlabel->ibank>>2]) { + curval=ae->bankgate[(curlabel->ibank&0x1FC)+(curlabel->ptr>>14)]; + } else { + curval=ae->bankgate[curlabel->ibank]; + } + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] cannot use PAGE - label [%s] is in a temporary space!\n",TradExpression(zeexpression),ae->computectx->varbuffer); + curval=curlabel->ibank; + } + break; + case 0:curval=curlabel->ibank;break; + default:MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INTERNAL ERROR (unknown paging)\n");FreeAssenv(ae);exit(-664); + } + } + } + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Label [%s](%d) cannot be computed because it is located after the crunched zone %d\n",ae->computectx->varbuffer,curlabel->lz,ae->expression[didx].lz); + curval=0; + } + } + } else { +#if TRACE_COMPUTE_EXPRESSION +printf("stage 2 | page=%d | ptr=%X ibank=%d\n",page,curlabel->ptr,curlabel->ibank); +#endif + if (bank) { + //curval=curlabel->ibank; + switch (page) { + case 2: /* PAGESET */ + if (curlabel->ibanksetgate[curlabel->ibank]; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] cannot use PAGESET - label [%s] is in a temporary space!\n",TradExpression(zeexpression),ae->computectx->varbuffer); + curval=curlabel->ibank; + } + break; + case 1:/* PAGE */ + if (curlabel->ibankbankset[curlabel->ibank>>2]) { + curval=ae->bankgate[(curlabel->ibank&0x1FC)+(curlabel->ptr>>14)]; + } else { + curval=ae->bankgate[curlabel->ibank]; + } + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] cannot use PAGE - label [%s] is in a temporary space!\n",TradExpression(zeexpression),ae->computectx->varbuffer); + curval=curlabel->ibank; + } + break; + case 0: + curval=curlabel->ibank; + break; + default:MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INTERNAL ERROR (unknown paging)\n",GetExpFile(ae,didx),GetExpLine(ae,didx));FreeAssenv(ae);exit(-664); + } + } else { + curval=curlabel->ptr; + } + } + } else { + /*********** + to allow aliases declared after use + ***********/ + if ((ialias=SearchAlias(ae,crc,ae->computectx->varbuffer+minusptr))>=0) { + newlen=ae->alias[ialias].len; + lenw=strlen(zeexpression); + if (newlen>ivar) { + /* realloc bigger */ + if (original) { + expr=MemMalloc(lenw+newlen-ivar+1); + memcpy(expr,zeexpression,lenw+1); + zeexpression=expr; + original=0; + } else { + zeexpression=MemRealloc(zeexpression,lenw+newlen-ivar+1); + } + } + /* startvar? */ + if (newlen!=ivar) { + MemMove(zeexpression+startvar+newlen,zeexpression+startvar+ivar,lenw-startvar-ivar+1); + } + strncpy(zeexpression+startvar,ae->alias[ialias].translation,newlen); /* copy without zero terminator */ + idx=startvar; + ivar=0; + continue; + } else { + /* index possible sur une struct? */ + int reverse_idx,validx=-1; + char *structlabel; + + reverse_idx=strlen(ae->computectx->varbuffer)-1; + if (ae->computectx->varbuffer[reverse_idx]>='0' && ae->computectx->varbuffer[reverse_idx]<='9') { + /* vu que ça ne PEUT PAS être une valeur litérale, on ne fait pas de test de débordement */ + reverse_idx--; + while (ae->computectx->varbuffer[reverse_idx]>='0' && ae->computectx->varbuffer[reverse_idx]<='9') { + reverse_idx--; + } + reverse_idx++; + validx=atoi(ae->computectx->varbuffer+reverse_idx); + structlabel=TxtStrDup(ae->computectx->varbuffer+minusptr); + structlabel[reverse_idx-minusptr]=0; +#if TRACE_STRUCT + printf("EVOL 119 -> looking for struct %s IDX=%d\n",structlabel,validx); +#endif + /* unoptimized search in structures aliases */ + crc=GetCRC(structlabel); + for (i=0;iirasmstructalias;i++) { + if (ae->rasmstructalias[i].crc==crc && strcmp(ae->rasmstructalias[i].name,structlabel)==0) { +#if TRACE_STRUCT + printf("EVOL 119 -> found! ptr=%d size=%d\n",ae->rasmstructalias[i].ptr,ae->rasmstructalias[i].size); +#endif + curval=ae->rasmstructalias[i].size*validx+ae->rasmstructalias[i].ptr; + if (validx>=ae->rasmstructalias[i].nbelem) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: index out of array size!\n",GetExpFile(ae,didx),GetExpLine(ae,didx)); + if (ae->erronwarn) MaxError(ae); + } + } + break; + } + } + if (i==ae->irasmstructalias) { + /* not found */ + validx=-1; + } + MemFree(structlabel); + } + if (validx<0) { + /* last chance to get a keyword */ + if (strcmp(ae->computectx->varbuffer+minusptr,"REPEAT_COUNTER")==0) { + if (ae->ir) { + curval=ae->repeat[ae->ir-1].repeat_counter; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"cannot use REPEAT_COUNTER keyword outside a repeat loop\n"); + curval=0; + } + } else if (strcmp(ae->computectx->varbuffer+minusptr,"WHILE_COUNTER")==0) { + if (ae->iw) { + curval=ae->whilewend[ae->iw-1].while_counter; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"cannot use WHILE_COUNTER keyword outside a while loop\n"); + curval=0; + } + } else { + /* in case the expression is a register */ + if (IsRegister(ae->computectx->varbuffer+minusptr)) { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"cannot use register %s in this context\n",TradExpression(zeexpression)); + } else { + if (IsDirective(ae->computectx->varbuffer+minusptr)) { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"cannot use directive %s in this context\n",TradExpression(zeexpression)); + } else { + + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] keyword [%s] not found in variables, labels or aliases\n",TradExpression(zeexpression),ae->computectx->varbuffer+minusptr); + if (ae->extended_error) { + char *lookstr; + lookstr=StringLooksLike(ae,ae->computectx->varbuffer+minusptr); + if (lookstr) { + rasm_printf(ae,KERROR" did you mean [%s] ?\n",lookstr); + } + } + } + } + + curval=0; + } + } + } + } + } + } + } + } + if (minusptr) curval=-curval; + stackelement.operator=E_COMPUTE_OPERATION_PUSH_DATASTC; + stackelement.value=curval; + /* priority isn't used */ + stackelement.string=NULL; + + allow_minus_as_sign=0; + ivar=0; + } + /************************************ + C R E A T E T O K E N + ************************************/ + ObjectArrayAddDynamicValueConcat((void **)&ae->computectx->tokenstack,&nbtokenstack,&ae->computectx->maxtokenstack,&stackelement,sizeof(stackelement)); + } + /******************************************************* + C R E A T E E X E C U T I O N S T A C K + *******************************************************/ +#define DEBUG_STACK 0 +#if DEBUG_STACK + for (itoken=0;itokencomputectx->tokenstack[itoken].operator) { + case E_COMPUTE_OPERATION_PUSH_DATASTC:printf("%lf %s",ae->computectx->tokenstack[itoken].value,ae->computectx->tokenstack[itoken].string?ae->computectx->tokenstack[itoken].string:"(null)");break; + case E_COMPUTE_OPERATION_OPEN:printf("(");break; + case E_COMPUTE_OPERATION_CLOSE:printf(")");break; + case E_COMPUTE_OPERATION_ADD:printf("+ ");break; + case E_COMPUTE_OPERATION_SUB:printf("- ");break; + case E_COMPUTE_OPERATION_DIV:printf("/ ");break; + case E_COMPUTE_OPERATION_MUL:printf("* ");break; + case E_COMPUTE_OPERATION_AND:printf("and ");break; + case E_COMPUTE_OPERATION_OR:printf("or ");break; + case E_COMPUTE_OPERATION_MOD:printf("mod ");break; + case E_COMPUTE_OPERATION_XOR:printf("xor ");break; + case E_COMPUTE_OPERATION_NOT:printf("! ");break; + case E_COMPUTE_OPERATION_SHL:printf("<< ");break; + case E_COMPUTE_OPERATION_SHR:printf(">> ");break; + case E_COMPUTE_OPERATION_BAND:printf("&& ");break; + case E_COMPUTE_OPERATION_BOR:printf("|| ");break; + case E_COMPUTE_OPERATION_LOWER:printf("< ");break; + case E_COMPUTE_OPERATION_GREATER:printf("> ");break; + case E_COMPUTE_OPERATION_EQUAL:printf("== ");break; + case E_COMPUTE_OPERATION_NOTEQUAL:printf("!= ");break; + case E_COMPUTE_OPERATION_LOWEREQ:printf("<= ");break; + case E_COMPUTE_OPERATION_GREATEREQ:printf(">= ");break; + case E_COMPUTE_OPERATION_SIN:printf("sin ");break; + case E_COMPUTE_OPERATION_COS:printf("cos ");break; + case E_COMPUTE_OPERATION_INT:printf("int ");break; + case E_COMPUTE_OPERATION_FLOOR:printf("floor ");break; + case E_COMPUTE_OPERATION_ABS:printf("abs ");break; + case E_COMPUTE_OPERATION_LN:printf("ln ");break; + case E_COMPUTE_OPERATION_LOG10:printf("log10 ");break; + case E_COMPUTE_OPERATION_SQRT:printf("sqrt ");break; + case E_COMPUTE_OPERATION_ASIN:printf("asin ");break; + case E_COMPUTE_OPERATION_ACOS:printf("acos ");break; + case E_COMPUTE_OPERATION_ATAN:printf("atan ");break; + case E_COMPUTE_OPERATION_EXP:printf("exp ");break; + case E_COMPUTE_OPERATION_LOW:printf("low ");break; + case E_COMPUTE_OPERATION_HIGH:printf("high ");break; + case E_COMPUTE_OPERATION_PSG:printf("psg ");break; + case E_COMPUTE_OPERATION_RND:printf("rnd ");break; + case E_COMPUTE_OPERATION_FRAC:printf("frac ");break; + case E_COMPUTE_OPERATION_CEIL:printf("ceil ");break; + case E_COMPUTE_OPERATION_GET_R:printf("get_r ");break; + case E_COMPUTE_OPERATION_GET_V:printf("get_v ");break; + case E_COMPUTE_OPERATION_GET_B:printf("get_b ");break; + case E_COMPUTE_OPERATION_SET_R:printf("set_r ");break; + case E_COMPUTE_OPERATION_SET_V:printf("set_v ");break; + case E_COMPUTE_OPERATION_SET_B:printf("set_b ");break; + case E_COMPUTE_OPERATION_SOFT2HARD:printf("soft2hard ");break; + case E_COMPUTE_OPERATION_HARD2SOFT:printf("hard2soft ");break; + case E_COMPUTE_OPERATION_GETNOP:printf("getnop ");break; + case E_COMPUTE_OPERATION_GETTICK:printf("gettick ");break; + case E_COMPUTE_OPERATION_DURATION:printf("duration ");break; + case E_COMPUTE_OPERATION_FILESIZE:printf("filesize ");break; + case E_COMPUTE_OPERATION_GETSIZE:printf("getsize ");break; + default:printf("bug\n");break; + } + + } + printf("\n"); +#endif + + for (itoken=0;itokencomputectx->tokenstack[itoken].operator) { + case E_COMPUTE_OPERATION_PUSH_DATASTC: +#if DEBUG_STACK +printf("data string=%X\n",ae->computectx->tokenstack[itoken].string); +#endif + ObjectArrayAddDynamicValueConcat((void **)&computestack,&nbcomputestack,&maxcomputestack,&ae->computectx->tokenstack[itoken],sizeof(stackelement)); + break; + case E_COMPUTE_OPERATION_OPEN: + ObjectArrayAddDynamicValueConcat((void **)&ae->computectx->operatorstack,&nboperatorstack,&ae->computectx->maxoperatorstack,&ae->computectx->tokenstack[itoken],sizeof(stackelement)); +#if DEBUG_STACK +printf("ajout ( string=%X\n",ae->computectx->tokenstack[itoken].string); +#endif + break; + case E_COMPUTE_OPERATION_CLOSE: +#if DEBUG_STACK +printf("close\n"); +#endif + /* pop out token until the opened parenthesis is reached */ + o2=nboperatorstack-1; + okclose=0; + while (o2>=0) { + if (ae->computectx->operatorstack[o2].operator!=E_COMPUTE_OPERATION_OPEN) { + ObjectArrayAddDynamicValueConcat((void **)&computestack,&nbcomputestack,&maxcomputestack,&ae->computectx->operatorstack[o2],sizeof(stackelement)); + nboperatorstack--; +#if DEBUG_STACK +printf("op-- string=%X\n",ae->computectx->operatorstack[o2].string); +#endif + o2--; + } else { + /* discard opening parenthesis as operator */ +#if DEBUG_STACK +printf("discard )\n"); +#endif + nboperatorstack--; + okclose=1; + o2--; + break; + } + } + if (!okclose) { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"missing parenthesis [%s]\n",TradExpression(zeexpression)); + if (!original) { + MemFree(zeexpression); + } + return 0; + } + /* if upper token is a function then pop from the stack */ + if (o2>=0 && ae->computectx->operatorstack[o2].operator>=E_COMPUTE_OPERATION_SIN) { + ObjectArrayAddDynamicValueConcat((void **)&computestack,&nbcomputestack,&maxcomputestack,&ae->computectx->operatorstack[o2],sizeof(stackelement)); + nboperatorstack--; +#if DEBUG_STACK +printf("pop function string=%X\n",ae->computectx->operatorstack[o2].string); +#endif + } + break; + case E_COMPUTE_OPERATION_ADD: + case E_COMPUTE_OPERATION_SUB: + case E_COMPUTE_OPERATION_DIV: + case E_COMPUTE_OPERATION_MUL: + case E_COMPUTE_OPERATION_AND: + case E_COMPUTE_OPERATION_OR: + case E_COMPUTE_OPERATION_MOD: + case E_COMPUTE_OPERATION_XOR: + case E_COMPUTE_OPERATION_NOT: + case E_COMPUTE_OPERATION_SHL: + case E_COMPUTE_OPERATION_SHR: + case E_COMPUTE_OPERATION_BAND: + case E_COMPUTE_OPERATION_BOR: + case E_COMPUTE_OPERATION_LOWER: + case E_COMPUTE_OPERATION_GREATER: + case E_COMPUTE_OPERATION_EQUAL: + case E_COMPUTE_OPERATION_NOTEQUAL: + case E_COMPUTE_OPERATION_LOWEREQ: + case E_COMPUTE_OPERATION_GREATEREQ: + o2=nboperatorstack-1; + while (o2>=0 && ae->computectx->operatorstack[o2].operator!=E_COMPUTE_OPERATION_OPEN) { + if (ae->computectx->tokenstack[itoken].priority>=ae->computectx->operatorstack[o2].priority || ae->computectx->operatorstack[o2].operator>=E_COMPUTE_OPERATION_SIN) { + ObjectArrayAddDynamicValueConcat((void **)&computestack,&nbcomputestack,&maxcomputestack,&ae->computectx->operatorstack[o2],sizeof(stackelement)); +#if DEBUG_STACK +printf("operator string=%X\n",ae->computectx->operatorstack[o2].string); +#endif + nboperatorstack--; + o2--; + } else { + break; + } + } + ObjectArrayAddDynamicValueConcat((void **)&ae->computectx->operatorstack,&nboperatorstack,&ae->computectx->maxoperatorstack,&ae->computectx->tokenstack[itoken],sizeof(stackelement)); + break; + case E_COMPUTE_OPERATION_SIN: + case E_COMPUTE_OPERATION_COS: + case E_COMPUTE_OPERATION_INT: + case E_COMPUTE_OPERATION_FLOOR: + case E_COMPUTE_OPERATION_ABS: + case E_COMPUTE_OPERATION_LN: + case E_COMPUTE_OPERATION_LOG10: + case E_COMPUTE_OPERATION_SQRT: + case E_COMPUTE_OPERATION_ASIN: + case E_COMPUTE_OPERATION_ACOS: + case E_COMPUTE_OPERATION_ATAN: + case E_COMPUTE_OPERATION_EXP: + case E_COMPUTE_OPERATION_LOW: + case E_COMPUTE_OPERATION_HIGH: + case E_COMPUTE_OPERATION_PSG: + case E_COMPUTE_OPERATION_RND: + case E_COMPUTE_OPERATION_FRAC: + case E_COMPUTE_OPERATION_CEIL: + case E_COMPUTE_OPERATION_GET_R: + case E_COMPUTE_OPERATION_GET_V: + case E_COMPUTE_OPERATION_GET_B: + case E_COMPUTE_OPERATION_SET_R: + case E_COMPUTE_OPERATION_SET_V: + case E_COMPUTE_OPERATION_SET_B: + case E_COMPUTE_OPERATION_SOFT2HARD: + case E_COMPUTE_OPERATION_HARD2SOFT: + case E_COMPUTE_OPERATION_GETNOP: + case E_COMPUTE_OPERATION_GETTICK: + case E_COMPUTE_OPERATION_DURATION: + case E_COMPUTE_OPERATION_FILESIZE: + case E_COMPUTE_OPERATION_GETSIZE: +#if DEBUG_STACK +printf("ajout de la fonction\n"); +#endif + ObjectArrayAddDynamicValueConcat((void **)&ae->computectx->operatorstack,&nboperatorstack,&ae->computectx->maxoperatorstack,&ae->computectx->tokenstack[itoken],sizeof(stackelement)); + break; + default:break; + } + } + /* pop remaining operators */ + while (nboperatorstack>0) { + ObjectArrayAddDynamicValueConcat((void **)&computestack,&nbcomputestack,&maxcomputestack,&ae->computectx->operatorstack[--nboperatorstack],sizeof(stackelement)); +#if DEBUG_STACK +printf("final POP string=%X\n",ae->computectx->operatorstack[nboperatorstack+1].string); +#endif + } + + /******************************************** + E X E C U T E S T A C K + ********************************************/ + if (ae->maxam || ae->as80) { + int workinterval; + if (ae->as80) workinterval=0xFFFFFFFF; else workinterval=0xFFFF; + for (i=0;i1) accu[paccu-2]=((int)accu[paccu-2]+(int)accu[paccu-1])&workinterval;paccu--;break; + case E_COMPUTE_OPERATION_SUB:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]-(int)accu[paccu-1])&workinterval;paccu--;break; + case E_COMPUTE_OPERATION_MUL:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]*(int)accu[paccu-1])&workinterval;paccu--;break; + case E_COMPUTE_OPERATION_DIV:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]/(int)accu[paccu-1])&workinterval;paccu--;break; + case E_COMPUTE_OPERATION_AND:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]&(int)accu[paccu-1])&workinterval;paccu--;break; + case E_COMPUTE_OPERATION_OR:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]|(int)accu[paccu-1])&workinterval;paccu--;break; + case E_COMPUTE_OPERATION_XOR:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]^(int)accu[paccu-1])&workinterval;paccu--;break; + case E_COMPUTE_OPERATION_MOD:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]%(int)accu[paccu-1])&workinterval;paccu--;break; + case E_COMPUTE_OPERATION_SHL:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2])<<((int)accu[paccu-1]); + if (((int)accu[paccu-1])>31 || ((int)accu[paccu-1])<-31) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning - shifting %d is architecture dependant, result forced to ZERO\n",GetExpFile(ae,didx),GetExpLine(ae,didx),(int)accu[paccu-1]); + if (ae->erronwarn) MaxError(ae); + } + accu[paccu-2]=0; + } + paccu--;break; + case E_COMPUTE_OPERATION_SHR:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2])>>((int)accu[paccu-1]); + if (((int)accu[paccu-1])>31 || ((int)accu[paccu-1])<-31) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning - shifting %d is architecture dependant, result forced to ZERO\n",GetExpFile(ae,didx),GetExpLine(ae,didx),(int)accu[paccu-1]); + if (ae->erronwarn) MaxError(ae); + } + accu[paccu-2]=0; + } + paccu--;break; + case E_COMPUTE_OPERATION_BAND:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]&&(int)accu[paccu-1])&workinterval;paccu--;break; + case E_COMPUTE_OPERATION_BOR:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]||(int)accu[paccu-1])&workinterval;paccu--;break; + /* comparison */ + case E_COMPUTE_OPERATION_LOWER:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]&workinterval)<((int)accu[paccu-1]&workinterval);paccu--;break; + case E_COMPUTE_OPERATION_LOWEREQ:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]&workinterval)<=((int)accu[paccu-1]&workinterval);paccu--;break; + case E_COMPUTE_OPERATION_EQUAL:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]&workinterval)==((int)accu[paccu-1]&workinterval);paccu--;break; + case E_COMPUTE_OPERATION_NOTEQUAL:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]&workinterval)!=((int)accu[paccu-1]&workinterval);paccu--;break; + case E_COMPUTE_OPERATION_GREATER:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]&workinterval)>((int)accu[paccu-1]&workinterval);paccu--;break; + case E_COMPUTE_OPERATION_GREATEREQ:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]&workinterval)>=((int)accu[paccu-1]&workinterval);paccu--;break; + /* functions */ + case E_COMPUTE_OPERATION_SIN:if (paccu>0) accu[paccu-1]=(int)sin(accu[paccu-1]*3.1415926545/180.0);break; + case E_COMPUTE_OPERATION_COS:if (paccu>0) accu[paccu-1]=(int)cos(accu[paccu-1]*3.1415926545/180.0);break; + case E_COMPUTE_OPERATION_ASIN:if (paccu>0) accu[paccu-1]=(int)asin(accu[paccu-1])*180.0/3.1415926545;break; + case E_COMPUTE_OPERATION_ACOS:if (paccu>0) accu[paccu-1]=(int)acos(accu[paccu-1])*180.0/3.1415926545;break; + case E_COMPUTE_OPERATION_ATAN:if (paccu>0) accu[paccu-1]=(int)atan(accu[paccu-1])*180.0/3.1415926545;break; + case E_COMPUTE_OPERATION_INT:break; + case E_COMPUTE_OPERATION_FLOOR:if (paccu>0) accu[paccu-1]=(int)floor(accu[paccu-1])&workinterval;break; + case E_COMPUTE_OPERATION_ABS:if (paccu>0) accu[paccu-1]=(int)fabs(accu[paccu-1])&workinterval;break; + case E_COMPUTE_OPERATION_EXP:if (paccu>0) accu[paccu-1]=(int)exp(accu[paccu-1])&workinterval;break; + case E_COMPUTE_OPERATION_LN:if (paccu>0) accu[paccu-1]=(int)log(accu[paccu-1])&workinterval;break; + case E_COMPUTE_OPERATION_LOG10:if (paccu>0) accu[paccu-1]=(int)log10(accu[paccu-1])&workinterval;break; + case E_COMPUTE_OPERATION_SQRT:if (paccu>0) accu[paccu-1]=(int)sqrt(accu[paccu-1])&workinterval;break; + case E_COMPUTE_OPERATION_LOW:if (paccu>0) accu[paccu-1]=((int)accu[paccu-1])&0xFF;break; + case E_COMPUTE_OPERATION_HIGH:if (paccu>0) accu[paccu-1]=(((int)accu[paccu-1])&0xFF00)>>8;break; + case E_COMPUTE_OPERATION_PSG:if (paccu>0) accu[paccu-1]=ae->psgfine[((int)accu[paccu-1])&0xFF];break; + case E_COMPUTE_OPERATION_RND:if (paccu>0) { + int zemod; + zemod=(int)floor(accu[paccu-1]+0.5); + if (zemod>0) { + accu[paccu-1]=FastRand()%zemod; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"RND function needs a value greater than zero to perform a random value\n"); + accu[paccu-1]=0; + } + } + break; + case E_COMPUTE_OPERATION_FRAC:if (paccu>0) accu[paccu-1]=((int)(accu[paccu-1]-(int)accu[paccu-1]));break; + case E_COMPUTE_OPERATION_CEIL:if (paccu>0) accu[paccu-1]=(int)ceil(accu[paccu-1])&workinterval;break; + case E_COMPUTE_OPERATION_GET_R:if (paccu>0) accu[paccu-1]=((((int)accu[paccu-1])&0xF0)>>4);break; + case E_COMPUTE_OPERATION_GET_V:if (paccu>0) accu[paccu-1]=((((int)accu[paccu-1])&0xF00)>>8);break; + case E_COMPUTE_OPERATION_GET_B:if (paccu>0) accu[paccu-1]=(((int)accu[paccu-1])&0xF);break; + case E_COMPUTE_OPERATION_SET_R:if (paccu>0) accu[paccu-1]=MinMaxInt(accu[paccu-1],0,15)<<4;break; + case E_COMPUTE_OPERATION_SET_V:if (paccu>0) accu[paccu-1]=MinMaxInt(accu[paccu-1],0,15)<<8;break; + case E_COMPUTE_OPERATION_SET_B:if (paccu>0) accu[paccu-1]=MinMaxInt(accu[paccu-1],0,15);break; + case E_COMPUTE_OPERATION_SOFT2HARD:if (paccu>0) accu[paccu-1]=__Soft2HardInk(ae,accu[paccu-1],didx);break; + case E_COMPUTE_OPERATION_HARD2SOFT:if (paccu>0) accu[paccu-1]=__Hard2SoftInk(ae,accu[paccu-1],didx);break; + /* functions with strings */ + case E_COMPUTE_OPERATION_GETNOP:if (paccu>0) { + int integeridx; + integeridx=floor(accu[paccu-1]); + + if (integeridx>=0 && integeridx=0 && integeridx0) { + int integeridx; + integeridx=floor(accu[paccu-1]); + + if (integeridx>=0 && integeridx=0 && integeridx0) { + int integeridx; + integeridx=floor(accu[paccu-1]); + + if (integeridx>=0 && integeridx=0 && integeridx0) { + int integeridx; + integeridx=floor(accu[paccu-1]); + + if (integeridx>=0 && integeridx=0 && integeridx0) { + int integeridx; + integeridx=floor(accu[paccu-1]); + + if (integeridx>=0 && integeridx=0 && integeridxwl[ae->idx].l,"invalid computing state! (%d)\n",computestack[i].operator);paccu=0; + } + if (!paccu) { + if (zeexpression[0]=='&') { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Missing operand for calculation [%s] Did you use & for an hexadecimal value?\n",TradExpression(zeexpression)); + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Missing operand for calculation [%s]\n",TradExpression(zeexpression)); + } + accu_err=1; + break; + } + } + } else { + for (i=0;i>": + computestack[i].operator==E_COMPUTE_OPERATION_LOWER?"<": + computestack[i].operator==E_COMPUTE_OPERATION_GREATER?">": + computestack[i].operator==E_COMPUTE_OPERATION_EQUAL?"==": + computestack[i].operator==E_COMPUTE_OPERATION_INT?"INT": + computestack[i].operator==E_COMPUTE_OPERATION_LOWEREQ?"<=": + computestack[i].operator==E_COMPUTE_OPERATION_GREATEREQ?">=": + computestack[i].operator==E_COMPUTE_OPERATION_OPEN?"(": + computestack[i].operator==E_COMPUTE_OPERATION_CLOSE?")": + computestack[i].operator==E_COMPUTE_OPERATION_GETNOP?"getnpo": + "",computestack[i].priority); + } +#endif + switch (computestack[i].operator) { + case E_COMPUTE_OPERATION_PUSH_DATASTC: + if (maccu<=paccu) { + maccu=16+paccu; + accu=MemRealloc(accu,sizeof(double)*maccu); + } + if (computestack[i].string) { + /* string hack */ + accu[paccu]=i+0.1; + } else { + accu[paccu]=computestack[i].value; + } + paccu++; + break; + case E_COMPUTE_OPERATION_OPEN: + case E_COMPUTE_OPERATION_CLOSE: /* cannot happend */ break; + case E_COMPUTE_OPERATION_ADD:if (paccu>1) accu[paccu-2]+=accu[paccu-1];paccu--;break; + case E_COMPUTE_OPERATION_SUB:if (paccu>1) accu[paccu-2]-=accu[paccu-1];paccu--;break; + case E_COMPUTE_OPERATION_MUL:if (paccu>1) accu[paccu-2]*=accu[paccu-1];paccu--;break; + case E_COMPUTE_OPERATION_DIV:if (paccu>1) accu[paccu-2]/=accu[paccu-1];paccu--;break; + case E_COMPUTE_OPERATION_AND:if (paccu>1) accu[paccu-2]=((int)floor(accu[paccu-2]+0.5))&((int)floor(accu[paccu-1]+0.5));paccu--;break; + case E_COMPUTE_OPERATION_OR:if (paccu>1) accu[paccu-2]=((int)floor(accu[paccu-2]+0.5))|((int)floor(accu[paccu-1]+0.5));paccu--;break; + case E_COMPUTE_OPERATION_XOR:if (paccu>1) accu[paccu-2]=((int)floor(accu[paccu-2]+0.5))^((int)floor(accu[paccu-1]+0.5));paccu--;break; + case E_COMPUTE_OPERATION_NOT:/* half operator, half function */ if (paccu>0) accu[paccu-1]=!((int)floor(accu[paccu-1]+0.5));break; + case E_COMPUTE_OPERATION_MOD:if (paccu>1) accu[paccu-2]=((int)floor(accu[paccu-2]+0.5))%((int)floor(accu[paccu-1]+0.5));paccu--;break; + case E_COMPUTE_OPERATION_SHL:if (paccu>1) accu[paccu-2]=((int)floor(accu[paccu-2]+0.5))<<((int)floor(accu[paccu-1]+0.5)); + if (((int)accu[paccu-1])>31 || ((int)accu[paccu-1])<-31) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning - shifting %d is architecture dependant, result forced to ZERO\n",GetExpFile(ae,didx),GetExpLine(ae,didx),(int)accu[paccu-1]); + if (ae->erronwarn) MaxError(ae); + } + accu[paccu-2]=0; + } + paccu--;break; + case E_COMPUTE_OPERATION_SHR:if (paccu>1) accu[paccu-2]=((int)floor(accu[paccu-2]+0.5))>>((int)floor(accu[paccu-1]+0.5)); + if (((int)accu[paccu-1])>31 || ((int)accu[paccu-1])<-31) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning - shifting %d is architecture dependant, result forced to ZERO\n",GetExpFile(ae,didx),GetExpLine(ae,didx),(int)accu[paccu-1]); + if (ae->erronwarn) MaxError(ae); + } + accu[paccu-2]=0; + } + paccu--;break; + case E_COMPUTE_OPERATION_BAND:if (paccu>1) accu[paccu-2]=((int)floor(accu[paccu-2]+0.5))&&((int)floor(accu[paccu-1]+0.5));paccu--;break; + case E_COMPUTE_OPERATION_BOR:if (paccu>1) accu[paccu-2]=((int)floor(accu[paccu-2]+0.5))||((int)floor(accu[paccu-1]+0.5));paccu--;break; + /* comparison */ + case E_COMPUTE_OPERATION_LOWER:if (paccu>1) accu[paccu-2]=accu[paccu-2]1) accu[paccu-2]=accu[paccu-2]<=accu[paccu-1];paccu--;break; + case E_COMPUTE_OPERATION_EQUAL:if (paccu>1) accu[paccu-2]=fabs(accu[paccu-2]-accu[paccu-1])<0.000001;paccu--;break; + case E_COMPUTE_OPERATION_NOTEQUAL:if (paccu>1) accu[paccu-2]=accu[paccu-2]!=accu[paccu-1];paccu--;break; + case E_COMPUTE_OPERATION_GREATER:if (paccu>1) accu[paccu-2]=accu[paccu-2]>accu[paccu-1];paccu--;break; + case E_COMPUTE_OPERATION_GREATEREQ:if (paccu>1) accu[paccu-2]=accu[paccu-2]>=accu[paccu-1];paccu--;break; + /* functions */ + case E_COMPUTE_OPERATION_SIN:if (paccu>0) accu[paccu-1]=sin(accu[paccu-1]*3.1415926545/180.0);break; + case E_COMPUTE_OPERATION_COS:if (paccu>0) accu[paccu-1]=cos(accu[paccu-1]*3.1415926545/180.0);break; + case E_COMPUTE_OPERATION_ASIN:if (paccu>0) accu[paccu-1]=asin(accu[paccu-1])*180.0/3.1415926545;break; + case E_COMPUTE_OPERATION_ACOS:if (paccu>0) accu[paccu-1]=acos(accu[paccu-1])*180.0/3.1415926545;break; + case E_COMPUTE_OPERATION_ATAN:if (paccu>0) accu[paccu-1]=atan(accu[paccu-1])*180.0/3.1415926545;break; + case E_COMPUTE_OPERATION_INT:if (paccu>0) accu[paccu-1]=floor(accu[paccu-1]+0.5);break; + case E_COMPUTE_OPERATION_FLOOR:if (paccu>0) accu[paccu-1]=floor(accu[paccu-1]);break; + case E_COMPUTE_OPERATION_ABS:if (paccu>0) accu[paccu-1]=fabs(accu[paccu-1]);break; + case E_COMPUTE_OPERATION_EXP:if (paccu>0) accu[paccu-1]=exp(accu[paccu-1]);break; + case E_COMPUTE_OPERATION_LN:if (paccu>0) accu[paccu-1]=log(accu[paccu-1]);break; + case E_COMPUTE_OPERATION_LOG10:if (paccu>0) accu[paccu-1]=log10(accu[paccu-1]);break; + case E_COMPUTE_OPERATION_SQRT:if (paccu>0) accu[paccu-1]=sqrt(accu[paccu-1]);break; + case E_COMPUTE_OPERATION_LOW:if (paccu>0) accu[paccu-1]=((int)floor(accu[paccu-1]+0.5))&0xFF;break; + case E_COMPUTE_OPERATION_HIGH:if (paccu>0) accu[paccu-1]=(((int)floor(accu[paccu-1]+0.5))&0xFF00)>>8;break; + case E_COMPUTE_OPERATION_PSG:if (paccu>0) accu[paccu-1]=ae->psgfine[((int)floor(accu[paccu-1]+0.5))&0xFF];break; + case E_COMPUTE_OPERATION_RND:if (paccu>0) { + int zemod; + zemod=(int)floor(accu[paccu-1]+0.5); + if (zemod>0) { + accu[paccu-1]=FastRand()%zemod; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"RND function needs a value greater than zero to perform a random value\n"); + accu[paccu-1]=0; + } + } + break; + case E_COMPUTE_OPERATION_FRAC:if (paccu>0) accu[paccu-1]=modf(accu[paccu-1],&dummint);break; + case E_COMPUTE_OPERATION_CEIL:if (paccu>0) accu[paccu-1]=ceil(accu[paccu-1]);break; + case E_COMPUTE_OPERATION_GET_R:if (paccu>0) accu[paccu-1]=((((int)accu[paccu-1])&0xF0)>>4);break; + case E_COMPUTE_OPERATION_GET_V:if (paccu>0) accu[paccu-1]=((((int)accu[paccu-1])&0xF00)>>8);break; + case E_COMPUTE_OPERATION_GET_B:if (paccu>0) accu[paccu-1]=(((int)accu[paccu-1])&0xF);break; + case E_COMPUTE_OPERATION_SET_R:if (paccu>0) accu[paccu-1]=MinMaxInt(accu[paccu-1],0,15)<<4;break; + case E_COMPUTE_OPERATION_SET_V:if (paccu>0) accu[paccu-1]=MinMaxInt(accu[paccu-1],0,15)<<8;break; + case E_COMPUTE_OPERATION_SET_B:if (paccu>0) accu[paccu-1]=MinMaxInt(accu[paccu-1],0,15);break; + case E_COMPUTE_OPERATION_SOFT2HARD:if (paccu>0) accu[paccu-1]=__Soft2HardInk(ae,accu[paccu-1],didx);break; + case E_COMPUTE_OPERATION_HARD2SOFT:if (paccu>0) accu[paccu-1]=__Hard2SoftInk(ae,accu[paccu-1],didx);break; + /* functions with strings */ + case E_COMPUTE_OPERATION_GETNOP:if (paccu>0) { + int integeridx; + integeridx=floor(accu[paccu-1]); + + if (integeridx>=0 && integeridx=0 && integeridx0) { + int integeridx; + integeridx=floor(accu[paccu-1]); + + if (integeridx>=0 && integeridx=0 && integeridx0) { + int integeridx; + integeridx=floor(accu[paccu-1]); + + if (integeridx>=0 && integeridx=0 && integeridx0) { + int integeridx; + integeridx=floor(accu[paccu-1]); + + if (integeridx>=0 && integeridx=0 && integeridx0) { + int integeridx; + integeridx=floor(accu[paccu-1]); + + if (integeridx>=0 && integeridx=0 && integeridxwl[ae->idx].l,"invalid computing state! (%d)\n",computestack[i].operator);paccu=0; + } + if (!paccu) { + if (zeexpression[0]=='&') { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Missing operand for calculation [%s] Did you use & for an hexadecimal value?\n",TradExpression(zeexpression)); + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Missing operand for calculation [%s]\n",TradExpression(zeexpression)); + } + accu_err=1; + break; + } + } + } + if (!original) { + MemFree(zeexpression); + } + if (paccu==1) { + return accu[0]; + } else if (!accu_err) { + if (paccu) { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Missing operator\n"); + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Missing operand for calculation\n"); + } + return 0; + } else { + return 0; + } +} +int RoundComputeExpressionCore(struct s_assenv *ae,char *zeexpression,int ptr,int didx) { + return floor(ComputeExpressionCore(ae,zeexpression,ptr,didx)+ae->rough); +} + +void ExpressionSetDicoVar(struct s_assenv *ae,char *name, double v, int var_external) +{ + #undef FUNC + #define FUNC "ExpressionSetDicoVar" + + struct s_expr_dico curdic; + curdic.name=TxtStrDup(name); + curdic.crc=GetCRC(name); + curdic.v=v; + curdic.iw=ae->idx; + curdic.autorise_export=ae->autorise_export; + curdic.external=var_external; + //ObjectArrayAddDynamicValueConcat((void**)&ae->dico,&ae->idic,&ae->mdic,&curdic,sizeof(curdic)); + if (SearchLabel(ae,curdic.name,curdic.crc)) { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"cannot create variable [%s] as there is already a label with the same name\n",name); + MemFree(curdic.name); + return; + } + InsertDicoToTree(ae,&curdic); +} + +double ComputeExpression(struct s_assenv *ae,char *expr, int ptr, int didx, int expected_eval) +{ + #undef FUNC + #define FUNC "ComputeExpression" + + char *ptr_exp,*ptr_exp2; + int crc,idx=0,ialias,touched; + double v; + struct s_alias curalias; + struct s_expr_dico *curdic; + + + while (!ae->AutomateExpressionDecision[((int)expr[idx])&0xFF]) idx++; + + switch (ae->AutomateExpressionDecision[((int)expr[idx])&0xFF]) { + /***************************************** + M A K E A L I A S + *****************************************/ + case '~': + memset(&curalias,0,sizeof(curalias)); + ptr_exp=expr+idx; + *ptr_exp=0; // on scinde l'alias de son texte + ptr_exp2=ptr_exp+1; +#if TRACE_COMPUTE_EXPRESSION +printf("MakeAlias (1) EXPR=[%s EQU %s]\n",expr,ptr_exp2); +#endif + + /* alias locaux ou de proximité */ + if (strchr("@.",expr[0])) { +#if TRACE_COMPUTE_EXPRESSION +printf("WARNING! alias is local! [%s]\n",expr); +#endif + /* local label creation does not handle formula in tags */ + curalias.alias=TranslateTag(ae,TxtStrDup(expr),&touched,0,E_TAGOPTION_NONE); + curalias.alias=MakeLocalLabel(ae,curalias.alias,NULL); + } else if (strchr(expr,'{')) { +#if TRACE_COMPUTE_EXPRESSION +printf("WARNING! alias has tag! [%s]\n",expr); +#endif + /* alias name contains formula */ + curalias.alias=TranslateTag(ae,TxtStrDup(expr),&touched,0,E_TAGOPTION_NONE); +#if TRACE_COMPUTE_EXPRESSION +printf("MakeAlias (2) EXPR=[%s EQU %s]\n",expr,ptr_exp2); +#endif + } else { + curalias.alias=TxtStrDup(expr); + } + curalias.crc=GetCRC(curalias.alias); + curalias.ptr=ae->codeadr; + curalias.lz=ae->ilz; + + if ((ialias=SearchAlias(ae,curalias.crc,curalias.alias))>=0) { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"Duplicate alias [%s]\n",expr); + MemFree(curalias.alias); + } else if (SearchDico(ae,curalias.alias,curalias.crc)) { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"Alias cannot override existing variable [%s]\n",expr); + MemFree(curalias.alias); + } else { + curalias.translation=MemMalloc(strlen(ptr_exp2)+1+2); + sprintf(curalias.translation,"(%s)",ptr_exp2); +#if TRACE_COMPUTE_EXPRESSION +printf("MakeAlias (3) EXPR=[%s EQU %s]\n",expr,ptr_exp2); +printf("alias translation [%s] -> ",curalias.translation);fflush(stdout); +#endif + ExpressionFastTranslate(ae,&curalias.translation,2); // FAST type 2 replace at least $ value +#if TRACE_COMPUTE_EXPRESSION +printf("%s\n",curalias.translation); +#endif + curalias.len=strlen(curalias.translation); + curalias.autorise_export=ae->autorise_export; + curalias.iw=ae->idx; + ObjectArrayAddDynamicValueConcat((void**)&ae->alias,&ae->ialias,&ae->malias,&curalias,sizeof(curalias)); + CheckAndSortAliases(ae); + } + *ptr_exp='~'; // on remet l'alias en place +#if TRACE_COMPUTE_EXPRESSION +printf("MakeAlias end with alias=[%s]=[%s]\n",curalias.alias,curalias.translation); +printf("***********\n"); +#endif + return 0; + /***************************************** + S E T V A R + *****************************************/ + case '=': + /* patch NOT + this is a variable assign if there is no other comparison operator after '=' + BUT we may have ! which stand for NOT but is also a comparison operator... + */ + if (ae->AutomateExpressionDecision[((int)expr[idx+1])&0xFF]==0 || expr[idx+1]=='!') { + if (expected_eval) { + if (ae->maxam) { + /* maxam mode AND expected a value -> force comparison */ + } else { + /* use of a single '=' but expected a comparison anyway */ + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"meaningless use of an expression [%s]\n",expr); + return 0; + } + } else { + /* ASSIGN */ + if ((expr[0]<'A' || expr[0]>'Z') && expr[0]!='_') { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"variable name must begin by a letter or '_' [%s]\n",expr); + return 0; + } else { + char operatorassignment; + + ptr_exp=expr+idx; + v=ComputeExpressionCore(ae,ptr_exp+1,ptr,didx); + *ptr_exp=0; + /* patch operator+assign value */ + switch (ptr_exp[-1]) { + case '+': + case '-': + case '*': + case '/': + case '^': + case '&': + case '|': + case '%': + case ']': + case '[': + operatorassignment=ptr_exp[-1];ptr_exp[-1]=0;break; + default:operatorassignment=0;break; + } + + crc=GetCRC(expr); + if ((ialias=SearchAlias(ae,crc,expr))>=0) { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"Variable cannot override existing alias [%s]\n",expr); + return 0; + } +#if TRACE_ASSEMBLE + printf("try to set [%s] with %lf operatorassignment=%c\n",expr,v,operatorassignment); +#endif + curdic=SearchDico(ae,expr,crc); + if (curdic) { + switch (operatorassignment) { + default:printf("warning remover\n");break; + case 0:curdic->v=v;break; + case '+':curdic->v+=v;ptr_exp[-1]='+';break; + case '-':curdic->v-=v;ptr_exp[-1]='-';break; + case '*':curdic->v*=v;ptr_exp[-1]='*';break; + case '/':curdic->v/=v;ptr_exp[-1]='/';break; + /* bit operations */ + case '|':curdic->v=((int)curdic->v)|((int)v);ptr_exp[-1]='|';break; + case '&':curdic->v=((int)curdic->v)&((int)v);ptr_exp[-1]='&';break; + case '^':curdic->v=((int)curdic->v)^((int)v);ptr_exp[-1]='^';break; + case '%':curdic->v=((int)curdic->v)%((int)v);ptr_exp[-1]='%';break; + case ']':curdic->v=((int)curdic->v)>>((int)v);ptr_exp[-1]=']'; + if (v>31 || v<-31) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"Warning - shifting %d is architecture dependant, result forced to ZERO\n",(int)v); + if (ae->erronwarn) MaxError(ae); + } + curdic->v=0; + } + break; + case '[':curdic->v=((int)curdic->v)<<((int)v);ptr_exp[-1]='['; + if (v>31 || v<-31) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"Warning - shifting %d is architecture dependant, result forced to ZERO\n",(int)v); + if (ae->erronwarn) MaxError(ae); + } + curdic->v=0; + } + break; + } + } else { + switch (operatorassignment) { + default: /* cannot do operator on non existing variable */ + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"Cannot do an operator assignment on non existing variable [%s]\n",expr); + return 0; + case 0: /* assign a new variable */ + ExpressionSetDicoVar(ae,expr,v,0); + break; + } + } + *ptr_exp='='; + return v; + } + } + } + break; + /***************************************** + P U R E E X P R E S S I O N + *****************************************/ + default:break; + } +#if TRACE_ASSEMBLE +printf("pure expression to compute [%s]\n",expr); +#endif + return ComputeExpressionCore(ae,expr,ptr,didx); +} +int RoundComputeExpression(struct s_assenv *ae,char *expr, int ptr, int didx, int expression_expected) { + return floor(ComputeExpression(ae,expr,ptr,didx,expression_expected)+ae->rough); +} + +/* + ExpressionFastTranslate + + purpose: translate all known symbols in an expression (especially variables acting like counters) + +0: +1: +2: (equ declaration) +*/ +void ExpressionFastTranslate(struct s_assenv *ae, char **ptr_expr, int fullreplace) +{ + #undef FUNC + #define FUNC "ExpressionFastTranslate" + + struct s_label *curlabel; + struct s_expr_dico *curdic; + static char *varbuffer=NULL; + static int ivar,maxivar=1; + char curval[256]={0}; + int c,lenw=0,idx=0,crc,startvar=0,newlen,ialias,found_replace,yves,dek,reidx,lenbuf,rlen,tagoffset; + double v; + char tmpuchar[16]; + char *expr,*locallabel; + int curly=0,curlyflag=0; + char *Automate; + int recurse=-1,recursecount=0; + + if (!ae || !ptr_expr) { + if (varbuffer) MemFree(varbuffer); + varbuffer=NULL; + maxivar=1; + ivar=0; + return; + } + /* be sure to have at least some bytes allocated */ + StateMachineResizeBuffer(&varbuffer,128,&maxivar); + expr=*ptr_expr; + + ivar=0; + +//printf("fast [%s]\n",expr); + + while (!ae->AutomateExpressionDecision[((int)expr[idx])&0xFF]) idx++; + + switch (ae->maxam) { + default: + case 0: /* full check */ + if (expr[idx]=='~' || (expr[idx]=='=' && expr[idx+1]!='=')) {reidx=idx+1;break;} + reidx=0; + break; + case 1: /* partial check with maxam */ + if (expr[idx]=='~') {reidx=idx+1;break;} + reidx=0; + break; + } + + idx=0; + /* is there ascii char? */ + while ((c=expr[idx])!=0) { + if (c=='\'' || c=='"') { + /* one char escape code */ + if (expr[idx+1]=='\\') { + if (expr[idx+2] && expr[idx+3]==c) { + /* no charset conversion for escaped chars */ + c=expr[idx+2]; + switch (c) { + case 'b':c='\b';break; + case 'v':c='\v';break; + case 'f':c='\f';break; + case '0':c='\0';break; + case 'r':c='\r';break; + case 'n':c='\n';break; + case 't':c='\t';break; + default:break; + } + sprintf(tmpuchar,"#%03X",c); + memcpy(expr+idx,tmpuchar,4); + idx+=3; + } else { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"expression [%s] - Only single escaped char may be quoted\n",expr); + expr[0]=0; + return; + } + } else if (expr[idx+1] && expr[idx+2]==c) { + sprintf(tmpuchar,"#%02X",ae->charset[((unsigned int)expr[idx+1])&0xFF]); + memcpy(expr+idx,tmpuchar,3); + idx+=2; + } else { + //printf("FAST => moar than one quoted char\n"); + //MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"expression [%s] - Only single char may be quoted\n",expr); + //expr[0]=0; + //return; + idx++; + while (expr[idx] && expr[idx]!=c) idx++; + } + } + idx++; + } + + idx=reidx; + while ((c=expr[idx])!=0) { + switch (c) { + /* string in expression */ + case '"': + case '\'': + //printf("FAST => skip string [%s]\n",expr); + idx++; + while (expr[idx] && expr[idx]!=c) idx++; + if (expr[idx]) idx++; + ivar=0; + break; + /* operator / parenthesis */ + case '!': + case '=': + case '>': + case '<': + case '(': + case ')': + case ']': + case '[': + case '*': + case '/': + case '+': + case '~': + case '-': + case '^': + case 'm': + case '|': + case '&': + idx++; + break; + default: + startvar=idx; + if (ae->AutomateExpressionValidCharFirst[((int)c)&0xFF]) { + varbuffer[ivar++]=c; + if (c=='{') { + /* this is only tag and not a formula */ + curly++; + } + StateMachineResizeBuffer(&varbuffer,ivar,&maxivar); + idx++; + c=expr[idx]; + + Automate=ae->AutomateExpressionValidChar; + while (Automate[((int)c)&0xFF]) { + if (c=='{') { + curly++; + curlyflag=1; + Automate=ae->AutomateExpressionValidCharExtended; + } else if (c=='}') { + curly--; + if (!curly) { + Automate=ae->AutomateExpressionValidChar; + } + } + varbuffer[ivar++]=c; + StateMachineResizeBuffer(&varbuffer,ivar,&maxivar); + idx++; + c=expr[idx]; + } + } + varbuffer[ivar]=0; + if (!ivar) { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"invalid expression [%s] c=[%c] idx=%d\n",expr,c,idx); + return; + } else if (curly) { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"wrong curly brackets in expression [%s]\n",expr); + return; + } + } + if (ivar && (varbuffer[0]<'0' || varbuffer[0]>'9')) { + /* numbering var or label */ + if (curlyflag) { + char *minivarbuffer; + int touched; + minivarbuffer=TranslateTag(ae,TxtStrDup(varbuffer), &touched,0,E_TAGOPTION_NONE|(fullreplace?0:E_TAGOPTION_PRESERVE)); + StateMachineResizeBuffer(&varbuffer,strlen(minivarbuffer)+1,&maxivar); + strcpy(varbuffer,minivarbuffer); + newlen=strlen(varbuffer); + lenw=strlen(expr); + /* must update source */ + if (newlen>ivar) { + /* realloc bigger */ + expr=*ptr_expr=MemRealloc(expr,lenw+newlen-ivar+1); + } + if (newlen!=ivar ) { + lenw=strlen(expr); + MemMove(expr+startvar+newlen,expr+startvar+ivar,lenw-startvar-ivar+1); + } + strncpy(expr+startvar,minivarbuffer,newlen); /* copy without zero terminator */ + idx=startvar+newlen; + /***/ + MemFree(minivarbuffer); + curlyflag=0; + /******* ivar must be updated in case of label or alias following ***********/ + ivar=newlen; + } + + /* recherche dans dictionnaire et remplacement */ + crc=GetCRC(varbuffer); + found_replace=0; + /* pour les affectations ou les tests conditionnels on ne remplace pas le dico (pour le Push oui par contre!) */ + if (fullreplace) { +//printf("ExpressionFastTranslate (full) => varbuffer=[%s] lz=%d\n",varbuffer,ae->lz); + if (varbuffer[0]=='$' && !varbuffer[1]) { + if (ae->lz==-1) { + #ifdef OS_WIN + snprintf(curval,sizeof(curval)-1,"%d",ae->codeadr); + newlen=strlen(curval); + #else + newlen=snprintf(curval,sizeof(curval)-1,"%d",ae->codeadr); + #endif + lenw=strlen(expr); + if (newlen>ivar) { + /* realloc bigger */ + expr=*ptr_expr=MemRealloc(expr,lenw+newlen-ivar+1); + } + if (newlen!=ivar ) { + MemMove(expr+startvar+newlen,expr+startvar+ivar,lenw-startvar-ivar+1); + found_replace=1; + } + strncpy(expr+startvar,curval,newlen); /* copy without zero terminator */ + idx=startvar+newlen; + ivar=0; + } + /* qu'on le remplace ou pas on passe a la suite */ + found_replace=1; + } else { + curdic=SearchDico(ae,varbuffer,crc); + if (curdic) { + v=curdic->v; +//printf("ExpressionFastTranslate (full) -> replace var (%s=%0.1lf)\n",varbuffer,v); + + #ifdef OS_WIN + snprintf(curval,sizeof(curval)-1,"%lf",v); + newlen=TrimFloatingPointString(curval); + #else + snprintf(curval,sizeof(curval)-1,"%lf",v); + newlen=TrimFloatingPointString(curval); + #endif + lenw=strlen(expr); + if (newlen>ivar) { + /* realloc bigger */ + expr=*ptr_expr=MemRealloc(expr,lenw+newlen-ivar+1); + } + if (newlen!=ivar ) { + MemMove(expr+startvar+newlen,expr+startvar+ivar,lenw-startvar-ivar+1); + } + strncpy(expr+startvar,curval,newlen); /* copy without zero terminator */ + idx=startvar+newlen; + ivar=0; + found_replace=1; + } + } + } + /* on cherche aussi dans les labels existants => priorité aux modules!!! */ // modulmodif => pas utile? + if (!found_replace) { + curlabel=SearchLabel(ae,varbuffer,crc); + if (curlabel) { + if (!curlabel->lz || ae->stage>1) { + yves=curlabel->ptr; + + #ifdef OS_WIN + snprintf(curval,sizeof(curval)-1,"%d",yves); + newlen=strlen(curval); + #else + newlen=snprintf(curval,sizeof(curval)-1,"%d",yves); + #endif + lenw=strlen(expr); + if (newlen>ivar) { + /* realloc bigger */ + expr=*ptr_expr=MemRealloc(expr,lenw+newlen-ivar+1); + } + if (newlen!=ivar ) { + MemMove(expr+startvar+newlen,expr+startvar+ivar,lenw-startvar-ivar+1); + } + strncpy(expr+startvar,curval,newlen); /* copy without zero terminator */ + found_replace=1; + idx=startvar+newlen; + ivar=0; + } + } + } + /* non trouve on cherche dans les alias */ + if (!found_replace) { + if ((ialias=SearchAlias(ae,crc,varbuffer))>=0) { + newlen=ae->alias[ialias].len; + lenw=strlen(expr); + /* infinite replacement check */ + if (recurse<=startvar) { + /* recurse maximum count is a mix of alias len and alias number */ + if (recursecount>ae->ialias+ae->alias[ialias].len) { + if (strchr(expr,'~')!=NULL) *strchr(expr,'~')=0; + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"alias definition of %s has infinite recursivity\n",expr); + expr[0]=0; /* avoid some errors due to shitty definition */ + return; + } else { + recursecount++; + } + } + if (newlen>ivar) { + /* realloc bigger */ + expr=*ptr_expr=MemRealloc(expr,lenw+newlen-ivar+1); + } + if (newlen!=ivar) { + MemMove(expr+startvar+newlen,expr+startvar+ivar,lenw-startvar-ivar+1); + } + strncpy(expr+startvar,ae->alias[ialias].translation,newlen); /* copy without zero terminator */ + found_replace=1; + /* need to parse again alias because of delayed declarations */ + recurse=startvar; + idx=startvar; + ivar=0; + } else { + } + } + if (!found_replace) { + //printf("fasttranslate test local label\n"); + /* non trouve c'est peut-etre un label local - mais pas de l'octal */ + if (varbuffer[0]=='@' && (varbuffer[1]<'0' || varbuffer[1]>'9')) { + char *zepoint; + lenbuf=strlen(varbuffer); +//printf("MakeLocalLabel(ae,varbuffer,&dek); (1)\n"); + locallabel=MakeLocalLabel(ae,varbuffer,&dek); +//printf("exprin =[%s] rlen=%d dek-lenbuf=%d\n",expr,rlen,dek-lenbuf); + /*** le grand remplacement ***/ + /* local to macro or loop */ + rlen=strlen(expr+startvar+lenbuf)+1; + expr=*ptr_expr=MemRealloc(expr,strlen(expr)+dek+1); + /* move end of expression in order to insert local ID */ + zepoint=strchr(varbuffer,'.'); + if (zepoint) { + /* far proximity access */ + int suffixlen,dotpos; + dotpos=(zepoint-varbuffer); + suffixlen=lenbuf-dotpos; + + MemMove(expr+startvar+dotpos+dek,expr+startvar+dotpos,rlen+suffixlen); + strncpy(expr+startvar+dotpos,locallabel,dek); + } else { + /* legacy */ + MemMove(expr+startvar+lenbuf+dek,expr+startvar+lenbuf,rlen); + strncpy(expr+startvar+lenbuf,locallabel,dek); + } + idx+=dek; + MemFree(locallabel); + found_replace=1; +//printf("exprout=[%s]\n",expr); + } else if (varbuffer[0]=='.' && (varbuffer[1]<'0' || varbuffer[1]>'9')) { + /* proximity label */ + lenbuf=strlen(varbuffer); +//printf("MakeLocalLabel(ae,varbuffer,&dek); (2)\n"); + locallabel=MakeLocalLabel(ae,varbuffer,&dek); + /*** le grand remplacement ***/ + rlen=strlen(expr+startvar+lenbuf)+1; + dek=strlen(locallabel); +//printf("exprin =[%s] rlen=%d dek-lenbuf=%d\n",expr,rlen,dek-lenbuf); + expr=*ptr_expr=MemRealloc(expr,strlen(expr)+dek-lenbuf+1); + MemMove(expr+startvar+dek,expr+startvar+lenbuf,rlen); + strncpy(expr+startvar,locallabel,dek); + idx+=dek-lenbuf; + MemFree(locallabel); +//printf("exprout=[%s]\n",expr); + +//@@TODO ajouter une recherche d'alias? + + } else if (varbuffer[0]=='{') { + if (strncmp(varbuffer,"{BANK}",6)==0 || strncmp(varbuffer,"{PAGE}",6)==0) tagoffset=6; else + if (strncmp(varbuffer,"{PAGESET}",9)==0) tagoffset=9; else + if (strncmp(varbuffer,"{SIZEOF}",8)==0) tagoffset=8; else + { + tagoffset=0; + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"Unknown prefix tag\n"); + } + + if (varbuffer[tagoffset]=='.') { + int lenadd; + startvar+=tagoffset; + lenbuf=strlen(varbuffer+tagoffset); + locallabel=MakeLocalLabel(ae,varbuffer+tagoffset,NULL); + /*** le grand remplacement meriterait une modif pour DEK dans MakeLocalLabel ***/ + rlen=strlen(expr+startvar+lenbuf)+1; + lenadd=strlen(locallabel)-strlen(varbuffer+tagoffset); + expr=*ptr_expr=MemRealloc(expr,strlen(expr)+lenadd+1); + +//printf("expr[%s] move to %d from %d len=%d\n",expr,startvar+lenadd,startvar,rlen+lenbuf); + MemMove(expr+startvar+lenadd,expr+startvar,rlen+lenbuf); + strncpy(expr+startvar,locallabel,lenadd); + + MemFree(locallabel); + found_replace=1; + idx+=lenadd; + } else if (varbuffer[tagoffset]=='@') { + char *zepoint; + startvar+=tagoffset; + lenbuf=strlen(varbuffer+tagoffset); +//printf("MakeLocalLabel(ae,varbuffer,&dek); (3)\n"); + locallabel=MakeLocalLabel(ae,varbuffer+tagoffset,&dek); +//printf("local [%s] =>",locallabel); + /*** le grand remplacement ***/ + rlen=strlen(expr+startvar+lenbuf)+1; + expr=*ptr_expr=MemRealloc(expr,strlen(expr)+dek+1); + /* move end of expression in order to insert local ID */ + zepoint=strchr(varbuffer+tagoffset,'.'); // +tagoffset + if (zepoint) { + /* far proximity access */ + int suffixlen,dotpos; + dotpos=(zepoint-varbuffer); + suffixlen=lenbuf-dotpos; + //printf("prox [%s] => ",expr); + MemMove(expr+startvar+dotpos+dek,expr+startvar+dotpos,rlen+suffixlen); + strncpy(expr+startvar+dotpos,locallabel,dek); + } else { + /* legacy */ + //printf("legacy [%s] => ",expr); + MemMove(expr+startvar+lenbuf+dek,expr+startvar+lenbuf,rlen); + strncpy(expr+startvar+lenbuf,locallabel,dek); + } + idx+=dek; + MemFree(locallabel); + found_replace=1; + //printf("exprout=[%s]\n",expr); + } else if (varbuffer[tagoffset]=='$') { + int tagvalue=-1; + /* + * There is no {SLOT}$ support... + */ + if (strcmp(varbuffer,"{BANK}$")==0) { + if (ae->forcecpr) { + if (ae->activebank<32) { + tagvalue=ae->activebank; + } else { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"expression [%s] cannot use BANK $ in a temporary space!\n",TradExpression(expr)); + tagvalue=0; + } + } else if (ae->forcesnapshot) { + if (ae->activebankbankset[ae->activebank>>2]) { + tagvalue=ae->activebank+(ae->codeadr>>14); /* dans un bankset on tient compte de l'adresse */ + } else { + tagvalue=ae->activebank; + } + + } else { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"expression [%s] cannot use BANK $ in a temporary space!\n",TradExpression(expr)); + tagvalue=0; + } + } + } else if (strcmp(varbuffer,"{PAGE}$")==0) { + if (ae->activebankbankset[ae->activebank>>2]) { + tagvalue=ae->bankgate[(ae->activebank&0x1FC)+(ae->codeadr>>14)]; + } else { + tagvalue=ae->bankgate[ae->activebank]; + } + } else { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"expression [%s] cannot use PAGE $ in a temporary space!\n",TradExpression(expr)); + tagvalue=ae->activebank; + } + } else if (strcmp(varbuffer,"{PAGESET}$")==0) { + if (ae->activebanksetgate[ae->activebank]; + //if (ae->activebank>3) tagvalue=((ae->activebank>>2)-1)*8+0xC2; else tagvalue=0xC0; + } else { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"expression [%s] cannot use PAGESET $ in a temporary space!\n",TradExpression(expr)); + tagvalue=ae->activebank; + } + } + /* replace */ + #ifdef OS_WIN + snprintf(curval,sizeof(curval)-1,"%d",tagvalue); + newlen=strlen(curval); + #else + newlen=snprintf(curval,sizeof(curval)-1,"%d",tagvalue); + #endif + lenw=strlen(expr); + if (newlen>ivar) { + /* realloc bigger */ + expr=*ptr_expr=MemRealloc(expr,lenw+newlen-ivar+1); + } + if (newlen!=ivar ) { + MemMove(expr+startvar+newlen,expr+startvar+ivar,lenw-startvar-ivar+1); + found_replace=1; + } + strncpy(expr+startvar,curval,newlen); /* copy without zero terminator */ + idx=startvar+newlen; + ivar=0; + found_replace=1; + } + } + } + + + + + + + if (!found_replace && strcmp(varbuffer,"REPEAT_COUNTER")==0) { + if (ae->ir) { + yves=ae->repeat[ae->ir-1].repeat_counter; + #ifdef OS_WIN + snprintf(curval,sizeof(curval)-1,"%d",yves); + newlen=strlen(curval); + #else + newlen=snprintf(curval,sizeof(curval)-1,"%d",yves); + #endif + lenw=strlen(expr); + if (newlen>ivar) { + /* realloc bigger */ + expr=*ptr_expr=MemRealloc(expr,lenw+newlen-ivar+1); + } + if (newlen!=ivar ) { + MemMove(expr+startvar+newlen,expr+startvar+ivar,lenw-startvar-ivar+1); + found_replace=1; + } + strncpy(expr+startvar,curval,newlen); /* copy without zero terminator */ + found_replace=1; + idx=startvar+newlen; + ivar=0; + } else { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"cannot use REPEAT_COUNTER outside repeat loop\n"); + } + } + if (!found_replace && strcmp(varbuffer,"WHILE_COUNTER")==0) { + if (ae->iw) { + yves=ae->whilewend[ae->iw-1].while_counter; + #ifdef OS_WIN + snprintf(curval,sizeof(curval)-1,"%d",yves); + newlen=strlen(curval); + #else + newlen=snprintf(curval,sizeof(curval)-1,"%d",yves); + #endif + lenw=strlen(expr); + if (newlen>ivar) { + /* realloc bigger */ + expr=*ptr_expr=MemRealloc(expr,lenw+newlen-ivar+1); + } + if (newlen!=ivar ) { + MemMove(expr+startvar+newlen,expr+startvar+ivar,lenw-startvar-ivar+1); + found_replace=1; + } + strncpy(expr+startvar,curval,newlen); /* copy without zero terminator */ + found_replace=1; + idx=startvar+newlen; + ivar=0; + } else { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"cannot use WHILE_COUNTER outside repeat loop\n"); + } + } + /* unknown symbol -> add to used symbol pool */ + if (!found_replace) { + InsertUsedToTree(ae,varbuffer,crc); + } + } + ivar=0; + } +} + +void PushExpression(struct s_assenv *ae,int iw,enum e_expression zetype) +{ + #undef FUNC + #define FUNC "PushExpression" + + struct s_expression curexp={0}; + int startptr=0; + + if (!ae->nocode) { + curexp.iw=iw; + curexp.wptr=ae->outputadr; + curexp.zetype=zetype; + curexp.ibank=ae->activebank; + curexp.iorgzone=ae->io-1; + curexp.lz=ae->lz; + /* need the module to know where we are */ + if (ae->module) curexp.module=TxtStrDup(ae->module); else curexp.module=NULL; + /* on traduit de suite les variables du dictionnaire pour les boucles et increments + SAUF si c'est une affectation + */ + if (!ae->wl[iw].e) { + switch (zetype) { + case E_EXPRESSION_J16C: + /* check non register usage */ + switch (GetCRC(ae->wl[iw].w)) { + case CRC_IX: + case CRC_IY: + case CRC_MIX: + case CRC_MIY: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"invalid register usage\n",ae->maxptr); + default:break; + } + case E_EXPRESSION_J8: + case E_EXPRESSION_V8: + case E_EXPRESSION_J16: + case E_EXPRESSION_V16: + case E_EXPRESSION_IM:startptr=-1; + break; + case E_EXPRESSION_IV8: + case E_EXPRESSION_IV81: + case E_EXPRESSION_IV16:startptr=-2; + break; + case E_EXPRESSION_3V8:startptr=-3; + break; + case E_EXPRESSION_RUN: + case E_EXPRESSION_ZXRUN: + case E_EXPRESSION_ZXSTACK: + case E_EXPRESSION_BRS:break; + default:break; + } + /* hack pourri pour gérer le $ */ + ae->codeadr+=startptr; + /* ok mais les labels locaux des macros? */ + + /* if external declared then fill some informations */ + if (ae->nexternal) { + switch (zetype) { + case E_EXPRESSION_0V8: + case E_EXPRESSION_V8: + case E_EXPRESSION_IV81: + case E_EXPRESSION_IV8: + case E_EXPRESSION_3V8: + ae->external_mapping_size=1; + break; + case E_EXPRESSION_J16C: + case E_EXPRESSION_J16: + case E_EXPRESSION_V16: + case E_EXPRESSION_0V16: + case E_EXPRESSION_IV16: + ae->external_mapping_size=2; + break; + case E_EXPRESSION_0V32: + ae->external_mapping_size=4; + break; + case E_EXPRESSION_0VR: + case E_EXPRESSION_0VRMike: + ae->external_mapping_size=5; + break; + default: + ae->external_mapping_size=0; + break; + } + } + if (ae->ir || ae->iw || ae->imacro) { + curexp.reference=TxtStrDup(ae->wl[iw].w); + ExpressionFastTranslate(ae,&curexp.reference,1); + } else { + ExpressionFastTranslate(ae,&ae->wl[iw].w,1); + } + ae->codeadr-=startptr; + } + /* calcul adresse de reference et post-incrementation pour sauter les data */ + switch (zetype) { + case E_EXPRESSION_J8:curexp.ptr=ae->codeadr-1;ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_0V8:curexp.ptr=ae->codeadr;ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_V8:curexp.ptr=ae->codeadr-1;ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_0V16:curexp.ptr=ae->codeadr;ae->outputadr+=2;ae->codeadr+=2;break; + case E_EXPRESSION_0V32:curexp.ptr=ae->codeadr;ae->outputadr+=4;ae->codeadr+=4;break; + case E_EXPRESSION_0VR:curexp.ptr=ae->codeadr;ae->outputadr+=5;ae->codeadr+=5;break; + case E_EXPRESSION_0VRMike:curexp.ptr=ae->codeadr;ae->outputadr+=5;ae->codeadr+=5;break; + case E_EXPRESSION_J16C: + case E_EXPRESSION_J16: + case E_EXPRESSION_V16:curexp.ptr=ae->codeadr-1;ae->outputadr+=2;ae->codeadr+=2;break; + case E_EXPRESSION_IV81:curexp.ptr=ae->codeadr-2;ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_IV8:curexp.ptr=ae->codeadr-2;ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_3V8:curexp.ptr=ae->codeadr-3;ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_IV16:curexp.ptr=ae->codeadr-2;ae->outputadr+=2;ae->codeadr+=2;break; + case E_EXPRESSION_RST:curexp.ptr=ae->codeadr;ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_IM:curexp.ptr=ae->codeadr-1;ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_RUN:break; + case E_EXPRESSION_ZXRUN:break; + case E_EXPRESSION_ZXSTACK:break; + case E_EXPRESSION_BRS:curexp.ptr=ae->codeadr;break; // minimum syndical + default:break; + } + /* le contrôle n'est pas bon avec les DEFB, DEFW, ... -> @@TODO */ + if (ae->outputadr<=ae->maxptr) { + ObjectArrayAddDynamicValueConcat((void **)&ae->expression,&ae->ie,&ae->me,&curexp,sizeof(curexp)); + } else { + /* to avoid double error message */ + if (!ae->stop) MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"output exceed limit %d\n",ae->maxptr); else MaxError(ae); + ae->stop=1; + return; + } + } else { + switch (zetype) { + case E_EXPRESSION_J8:ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_0V8:ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_V8:ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_0V16:ae->outputadr+=2;ae->codeadr+=2;break; + case E_EXPRESSION_0V32:ae->outputadr+=4;ae->codeadr+=4;break; + case E_EXPRESSION_0VR:ae->outputadr+=5;ae->codeadr+=5;break; + case E_EXPRESSION_0VRMike:ae->outputadr+=5;ae->codeadr+=5;break; + case E_EXPRESSION_J16C: + case E_EXPRESSION_J16: + case E_EXPRESSION_V16:ae->outputadr+=2;ae->codeadr+=2;break; + case E_EXPRESSION_IV81:ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_IV8:ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_3V8:ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_IV16:ae->outputadr+=2;ae->codeadr+=2;break; + case E_EXPRESSION_RST:ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_IM:ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_RUN:break; + case E_EXPRESSION_ZXRUN:break; + case E_EXPRESSION_ZXSTACK:break; + case E_EXPRESSION_BRS:break; + } + if (ae->outputadr<=ae->maxptr) { + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"NOCODE output exceed limit %d\n",ae->maxptr); + FreeAssenv(ae);exit(3); + } + } +} + +/* +The CP/M 2.2 directory has only one type of entry: + +UU F1 F2 F3 F4 F5 F6 F7 F8 T1 T2 T3 EX S1 S2 RC .FILENAMETYP.... +AL AL AL AL AL AL AL AL AL AL AL AL AL AL AL AL ................ + +UU = User number. 0-15 (on some systems, 0-31). The user number allows multiple + files of the same name to coexist on the disc. + User number = 0E5h => File deleted +Fn - filename +Tn - filetype. The characters used for these are 7-bit ASCII. + The top bit of T1 (often referred to as T1') is set if the file is + read-only. + T2' is set if the file is a system file (this corresponds to "hidden" on + other systems). +EX = Extent counter, low byte - takes values from 0-31 +S2 = Extent counter, high byte. + + An extent is the portion of a file controlled by one directory entry. + If a file takes up more blocks than can be listed in one directory entry, + it is given multiple entries, distinguished by their EX and S2 bytes. The + formula is: Entry number = ((32*S2)+EX) / (exm+1) where exm is the + extent mask value from the Disc Parameter Block. + +S1 - reserved, set to 0. +RC - Number of records (1 record=128 bytes) used in this extent, low byte. + The total number of records used in this extent is + + (EX & exm) * 128 + RC + + If RC is 80h, this extent is full and there may be another one on the disc. + File lengths are only saved to the nearest 128 bytes. + +AL - Allocation. Each AL is the number of a block on the disc. If an AL + number is zero, that section of the file has no storage allocated to it + (ie it does not exist). For example, a 3k file might have allocation + 5,6,8,0,0.... - the first 1k is in block 5, the second in block 6, the + third in block 8. + AL numbers can either be 8-bit (if there are fewer than 256 blocks on the + disc) or 16-bit (stored low byte first). +*/ +int EDSK_getblockid(int *fb) { + #undef FUNC + #define FUNC "EDSK_getblockid" + + int i; + for (i=0;i<180;i++) { + if (fb[i]) { + return i; + } + } + return -1; +} +int EDSK_getdirid(struct s_edsk_wrapper *curwrap) { + #undef FUNC + #define FUNC "EDSK_getdirid" + + int ie; + for (ie=0;ie<64;ie++) { + if (curwrap->entry[ie].user==0xE5) { +#if TRACE_EDSK + printf("getdirid returns %d\n",ie); +#endif + return ie; + } + } + return -1; +} +char *MakeAMSDOS_name(struct s_assenv *ae, char *reference_filename) +{ + #undef FUNC + #define FUNC "MakeAMSDOS_name" + + static char amsdos_name[12]; + char *filename,*jo; + int i,ia; + char *pp; + + /* remove path */ + filename=reference_filename; + while ((jo=strchr(filename,'/'))!=NULL) filename=jo+1; + while ((jo=strchr(filename,'\\'))!=NULL) filename=jo+1; + + /* warning */ + if (strlen(filename)>12) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"Warning - filename [%s] too long for AMSDOS, will be truncated\n",filename); + if (ae->erronwarn) MaxError(ae); + } + } else if ((pp=strchr(filename,'.'))!=NULL) { + if (pp-filename>8) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"Warning - filename [%s] too long for AMSDOS, will be truncated\n",filename); + if (ae->erronwarn) MaxError(ae); + } + } + } + /* copy filename */ + for (i=0;filename[i]!=0 && filename[i]!='.' && i<8;i++) { + amsdos_name[i]=toupper(filename[i]); + } + /* fill with spaces */ + for (ia=i;ia<8;ia++) { + amsdos_name[ia]=0x20; + } + /* looking for extension */ + for (;filename[i]!=0 && filename[i]!='.';i++); + /* then copy it if any */ + if (filename[i]=='.') { + i++; + for (ia=0;filename[i]!=0 && ia<3;ia++) { + amsdos_name[8+ia]=toupper(filename[i++]); + } + } + amsdos_name[11]=0; +#if TRACE_EDSK + printf("MakeAMSDOS_name [%s] -> [%s]\n",filename,amsdos_name); +#endif + return amsdos_name; +} + + +void EDSK_load(struct s_assenv *ae,struct s_edsk_wrapper *curwrap, char *edskfilename, int face) +{ + #undef FUNC + #define FUNC "EDSK_load" + + unsigned char header[256]; + unsigned char *data; + int tracknumber,sidenumber,tracksize,disksize; + int i,b,s,f,t,curtrack,sectornumber,sectorsize,sectorid,reallength; + int currenttrackposition=0,currentsectorposition,tmpcurrentsectorposition; + unsigned char checksectorid[9]; + int curblock=0,curoffset=0; +#if TRACE_EDSK + printf("EDSK_Load('%s',%d);",edskfilename,face); +#endif + if (FileReadBinary(edskfilename,(char*)&header,0x100)!=0x100) { + rasm_printf(ae,KERROR"Cannot read EDSK header of [%s]!\n",edskfilename); + FreeAssenv(ae);exit(ABORT_ERROR); + } + if (strncmp((char *)header,"MV - CPC",8)==0) { + rasm_printf(ae,KAYGREEN"updating DSK to EDSK [%s] / creator: %s",edskfilename,header+34); + + tracknumber=header[34+14]; + sidenumber=header[34+14+1]; + tracksize=header[34+14+1+1]+header[34+14+1+1+1]*256; + rasm_printf(ae,"tracks: %d sides:%d track size:%d",tracknumber,sidenumber,tracksize); + if (tracknumber>40 || sidenumber>2) { + rasm_printf(ae,KERROR"[%s] DSK format is not supported in update mode (ntrack=%d nside=%d)\n",edskfilename,tracknumber,sidenumber); + FreeAssenv(ae);exit(ABORT_ERROR); + } + if (face>=sidenumber) { + rasm_printf(ae,KWARNING"[%s] Warning - DSK has no face %d - DSK updated\n",edskfilename,face); + if (ae->erronwarn) MaxError(ae); + return; + } + + data=MemMalloc(tracksize*tracknumber*sidenumber); + memset(data,0,tracksize*tracknumber*sidenumber); + if (FileReadBinary(edskfilename,(char *)data,tracksize*tracknumber*sidenumber)!=tracksize*tracknumber*sidenumber) { + rasm_printf(ae,"Cannot read DSK tracks!"); + FreeAssenv(ae);exit(ABORT_ERROR); + } + //loginfo("track data read (%dkb)",tracksize*tracknumber*sidenumber/1024); + f=face; + for (t=0;t0xC9) { + rasm_printf(ae,"Invalid sector ID in sector %02X track %d",data[i+24+8*s+2],t); + FreeAssenv(ae);exit(ABORT_ERROR); + } else { + checksectorid[data[i+24+8*s+2]-0xC1]=1; + } + if (data[i+24+8*s+3]!=2) { + rasm_printf(ae,"Invalid sector size in sector %02X track %d",data[i+24+8*s+2],t); + FreeAssenv(ae);exit(ABORT_ERROR); + } + } + for (s=0;sblocks[curblock][curoffset],&data[i+0x100+s*512],512); + curoffset+=512; + if (curoffset>=1024) { + curoffset=0; + curblock++; + } + } + } + } + } else if (strncmp((char *)header,"EXTENDED",8)==0) { + rasm_printf(ae,KAYGREEN"updating EDSK [%s] / creator: %-14.14s\n",edskfilename,header+34); + tracknumber=header[34+14]; + sidenumber=header[34+14+1]; + // not in EDSK tracksize=header[34+14+1+1]+header[34+14+1+1+1]*256; +#if TRACE_EDSK + loginfo("tracks: %d sides:%d",tracknumber,sidenumber); +#endif + + if (sidenumber>2) { + rasm_printf(ae,KERROR"[%s] EDSK format is not supported in update mode (ntrack=%d nside=%d)\n",edskfilename,tracknumber,sidenumber); + FreeAssenv(ae);exit(ABORT_ERROR); + } + if (face>=sidenumber) { + rasm_printf(ae,KWARNING"[%s] EDSK has no face %d - DSK updated\n",edskfilename,face); + if (ae->erronwarn) MaxError(ae); + return; + } + + for (i=disksize=0;i=0xC1 && sectorid<=0xC9) checksectorid[sectorid-0xC1]=1; else { + rasm_printf(ae,KERROR"invalid sector id %02X for DATA track %d\n",sectorid,t); + return; + } + sectorsize=data[i+24+8*s+3]; + if (sectorsize!=2) { + rasm_printf(ae,KERROR"invalid sector size track %d\n",t); + return; + } + reallength=data[i+24+8*s+6]+data[i+24+8*s+7]*256; /* real length stored */ + if (reallength!=512) { + rasm_printf(ae,KERROR"invalid sector length %d for track %d\n",reallength,t); + return; + } +#if TRACE_EDSK + printf("%02X ",sectorid); +#endif + } + if (track_sectorsize!=2) { + rasm_printf(ae,KWARNING"track %02d has invalid sector size but sectors are OK\n",t); + if (ae->erronwarn) MaxError(ae); + } +#if TRACE_EDSK + printf("\n"); +#endif + + /* piste à piste on lit les blocs DANS L'ORDRE LOGIQUE!!! */ + for (b=0xC1;b<=0xC9;b++) { + tmpcurrentsectorposition=currentsectorposition; + for (s=0;sblocks[curblock][curoffset],&data[tmpcurrentsectorposition],512); + curoffset+=512; + if (curoffset>=1024) { + curoffset=0; + curblock++; + } + } + reallength=data[i+24+8*s+6]+data[i+24+8*s+7]*256; + tmpcurrentsectorposition+=reallength; + } + } + } + } + + + } else { + rasm_printf(ae,KERROR"file [%s] is not a valid (E)DSK floppy image\n",edskfilename); + FreeAssenv(ae);exit(-923); + } + FileReadBinaryClose(edskfilename); + + /* Rasm management of (e)DSK files is AMSDOS compatible, just need to copy CATalog blocks but sort them... */ + memcpy(&curwrap->entry[0],curwrap->blocks[0],1024); + memcpy(&curwrap->entry[32],curwrap->blocks[1],1024); + /* tri des entrées selon le user */ + qsort(curwrap->entry,64,sizeof(struct s_edsk_wrapper_entry),cmpAmsdosentry); + curwrap->nbentry=64; + for (i=0;i<64;i++) { + if (curwrap->entry[i].user==0xE5) { + curwrap->nbentry=i; + break; + } + } +#if TRACE_EDSK + printf("%d entr%s found\n",curwrap->nbentry,curwrap->nbentry>1?"ies":"y"); + for (i=0;inbentry;i++) { + printf("[%02d] - ",i); + if (curwrap->entry[i].user<16) { + printf("U%02d [%-8.8s.%c%c%c] %c%c subcpt=#%02X rc=#%02X blocks=",curwrap->entry[i].user,curwrap->entry[i].filename, + curwrap->entry[i].filename[8]&0x7F,curwrap->entry[i].filename[9]&0x7F,curwrap->entry[i].filename[10], + curwrap->entry[i].filename[8]&0x80?'P':'-',curwrap->entry[i].filename[9]&0x80?'H':'-', + curwrap->entry[i].subcpt,curwrap->entry[i].rc); + for (b=0;b<16;b++) if (curwrap->entry[i].blocks[b]) printf("%s%02X",b>0?" ":"",curwrap->entry[i].blocks[b]); else printf("%s ",b>0?" ":""); + if (i&1) printf("\n"); else printf(" | "); + } else { + printf("free entry = rc= blocks= "); + if (i&1) printf("\n"); else printf(" | "); + } + } + if (i&1) printf("\n"); +#endif +} + +struct s_edsk_wrapper *EDSK_select(struct s_assenv *ae,char *edskfilename, int facenumber) +{ + #undef FUNC + #define FUNC "EDSK_select" + + struct s_edsk_wrapper newwrap={0},*curwrap=NULL; + int i; +#if TRACE_EDSK + printf("EDSK_select('%s',%d);\n",edskfilename,facenumber); +#endif + /* check if there is a DSK in memory */ + for (i=0;inbedskwrapper;i++) { + if (!strcmp(ae->edsk_wrapper[i].edsk_filename,edskfilename)) { +#if TRACE_EDSK + printf("Found! return %d\n",i); +#endif + return &ae->edsk_wrapper[i]; + } + } + /* not in memory, create an empty struct */ + newwrap.edsk_filename=TxtStrDup(edskfilename); + memset(newwrap.entry,0xE5,sizeof(struct s_edsk_wrapper_entry)*64); + memset(newwrap.blocks[0],0xE5,1024); + memset(newwrap.blocks[1],0xE5,1024); +#if TRACE_EDSK + printf("Not found! create empty struct\n"); +#endif + newwrap.face=facenumber; + ObjectArrayAddDynamicValueConcat((void**)&ae->edsk_wrapper,&ae->nbedskwrapper,&ae->maxedskwrapper,&newwrap,sizeof(struct s_edsk_wrapper)); + /* and load files if the DSK exists on disk */ + curwrap=&ae->edsk_wrapper[ae->nbedskwrapper-1]; + if (FileExists(edskfilename)) { + EDSK_load(ae,curwrap,edskfilename,facenumber); + } + return curwrap; +} + +int EDSK_addfile(struct s_assenv *ae,char *edskfilename,int facenumber, char *filename,unsigned char *indata,int insize, int offset, int run) +{ + #undef FUNC + #define FUNC "EDSK_addfile" + + struct s_edsk_wrapper *curwrap=NULL; + char amsdos_name[12]={0}; + int j,i,ia,ib,ie,filesize,idxdata; + int fb[180],rc,idxb; + unsigned char *data=NULL; + int size=0; + int firstblock; + + curwrap=EDSK_select(ae,edskfilename,facenumber); + /* update struct */ + size=insize+128; + data=MemMalloc(size); + strcpy(amsdos_name,MakeAMSDOS_name(ae,filename)); + memcpy(data,MakeAMSDOSHeader(run,offset,offset+insize,amsdos_name),128); + memcpy(data+128,indata,insize); + /* overwrite check */ +#if TRACE_EDSK + printf("EDSK_addfile will checks %d entr%s for [%s]\n",curwrap->nbentry,curwrap->nbentry>1?"ies":"y",amsdos_name); +#endif + for (i=0;inbentry;i++) { + if (!strncmp((char *)curwrap->entry[i].filename,amsdos_name,11)) { + if (!ae->edskoverwrite) { + MakeError(ae,NULL,0,"Error - Cannot save [%s] in edsk [%s] with overwrite disabled as the file already exists\n",amsdos_name,edskfilename); + MemFree(data); + return 0; + } else { + /* overwriting previous file */ +#if TRACE_EDSK + printf(" -> reset previous entry %d with 0xE5\n",i); +#endif + memset(&curwrap->entry[i],0xE5,sizeof(struct s_edsk_wrapper_entry)); + } + } + } + /* find free blocks */ +#if TRACE_EDSK + printf("EDSK_addfile find free blocks\n"); +#endif + fb[0]=fb[1]=0; + for (i=2;i<180;i++) fb[i]=1; + for (i=0;inbentry;i++) { + if (curwrap->entry[i].rc!=0xE5 && curwrap->entry[i].rc!=0) { + /* entry found, compute number of blocks to read */ + rc=curwrap->entry[i].rc/8; + if (curwrap->entry[i].rc%8) rc++; /* adjust value */ + /* mark as used */ + for (j=0;jentry[i].blocks[j]]=0; + } + } + } + /* set directory, blocks and data in blocks */ + firstblock=-1; + filesize=size; + idxdata=0; + ia=0; + +#if TRACE_EDSK + printf("Writing [%s] size=%d\n",amsdos_name,size); +#endif + + while (filesize>0) { + if (filesize>16384) { + /* extended entry */ +#if TRACE_EDSK + printf("extended entry for file (filesize=%d)\nblocklist: ",filesize); +#endif + if ((ie=EDSK_getdirid(curwrap))==-1) { + MakeError(ae,NULL,0,"Error - edsk [%s] DIRECTORY FULL\n",edskfilename); + MemFree(data); + return 0; + } + if (curwrap->nbentry<=ie) curwrap->nbentry=ie+1; + idxb=0; + for (i=0;i<16;i++) { + if ((ib=EDSK_getblockid(fb))==-1) { + MakeError(ae,NULL,0,"Error - edsk [%s] DISK FULL\n",edskfilename); + MemFree(data); + return 0; + } else { + if (firstblock==-1) firstblock=ib; + +#if TRACE_EDSK + printf("%02X ",ib); +#endif + memcpy(curwrap->blocks[ib],data+idxdata,1024); + idxdata+=1024; + filesize-=1024; + fb[ib]=0; + curwrap->entry[ie].blocks[idxb++]=ib; + } + } +#if TRACE_EDSK + printf("\n"); +#endif + memcpy(curwrap->entry[ie].filename,amsdos_name,11); + curwrap->entry[ie].subcpt=ia; + curwrap->entry[ie].rc=0x80; + curwrap->entry[ie].user=0; + ia++; + idxb=0; + } else { + /* last entry */ +#if TRACE_EDSK + printf("last entry for file (filesize=%d)\nblocklist: ",filesize); +#endif + if ((ie=EDSK_getdirid(curwrap))==-1) { + MakeError(ae,NULL,0,"Error - edsk [%s] DIRECTORY FULL\n",edskfilename); + MemFree(data); + return 0; + } + if (curwrap->nbentry<=ie) curwrap->nbentry=ie+1; + /* calcul du nombre de sous blocs de 128 octets */ + curwrap->entry[ie].rc=filesize/128; + if (filesize%128) { + curwrap->entry[ie].rc+=1; + } + idxb=0; + for (i=0;i<16 && filesize>0;i++) { + if ((ib=EDSK_getblockid(fb))==-1) { + MakeError(ae,NULL,0,"Error - edsk [%s] DISK FULL\n",edskfilename); + MemFree(data); + return 0; + } else { + if (firstblock==-1) firstblock=ib; +#if TRACE_EDSK + printf("%02X ",ib); +#endif + + memcpy(curwrap->blocks[ib],&data[idxdata],filesize>1024?1024:filesize); + idxdata+=1024; + filesize-=1024; + fb[ib]=0; + curwrap->entry[ie].blocks[idxb++]=ib; + } + } +#if TRACE_EDSK + printf("\n"); +#endif + filesize=0; + memcpy(curwrap->entry[ie].filename,amsdos_name,11); + curwrap->entry[ie].subcpt=ia; + curwrap->entry[ie].user=0; + } + } + + MemFree(data); + return 1; +} + +void EDSK_build_amsdos_directory(struct s_edsk_wrapper *face) +{ + #undef FUNC + #define FUNC "EDSK_build_amsdos_directory" + + unsigned char amsdosdir[2048]={0}; + int i,idx=0,b; + + if (!face) return; + +#if TRACE_EDSK +printf("build amsdos dir with %d entries\n",face->nbentry); +#endif + for (i=0;inbentry;i++) { + if (face->entry[i].rc && face->entry[i].rc!=0xE5) { + amsdosdir[idx]=face->entry[i].user; + memcpy(amsdosdir+idx+1,face->entry[i].filename,11); + amsdosdir[idx+12]=face->entry[i].subcpt; + amsdosdir[idx+13]=0; + amsdosdir[idx+14]=0; + amsdosdir[idx+15]=face->entry[i].rc; +#if TRACE_EDSK +printf("%-11.11s [%02X.%02X] blocks:",amsdosdir+idx+1,amsdosdir[idx+12],amsdosdir[idx+15]); +#endif + for (b=0;b<16;b++) { + if (face->entry[i].blocks[b]!=0xE5) { + amsdosdir[idx+16+b]=face->entry[i].blocks[b]; +#if TRACE_EDSK + printf("%s%02X",b>0?".":"",amsdosdir[idx+16+b]); +#endif + } else { + amsdosdir[idx+16+b]=0; + } + } +#if TRACE_EDSK +printf("\n"); +#endif + } + idx+=32; + } +#if TRACE_EDSK +printf("filling amsdos remaining entries (%d) with #E5\n",64-face->nbentry); +#endif + memset(amsdosdir+idx,0xE5,32*(64-face->nbentry)); + + /* AMSDOS directory copy to blocks! */ + memcpy(face->blocks[0],amsdosdir,1024); + memcpy(face->blocks[1],amsdosdir+1024,1024); +} +void EDSK_write_file(struct s_assenv *ae,struct s_edsk_wrapper *faceA,struct s_edsk_wrapper *faceB) +{ + #undef FUNC + #define FUNC "EDSK_write_file" + + struct s_edsk_wrapper emptyface={0}; + unsigned char header[256]={0}; + unsigned char trackblock[256]={0}; + unsigned char headertag[25]; + int idblock,blockoffset; + int i,t; + + if (!faceA && !faceB) return; + + /* création des deux blocs du directory par face */ + EDSK_build_amsdos_directory(faceA); + EDSK_build_amsdos_directory(faceB); + /* écriture header */ + strcpy((char *)header,"EXTENDED CPC DSK File\r\nDisk-Info\r\n"); + sprintf(headertag,"%-9.9s",RASM_SNAP_VERSION); + strcpy((char *)header+0x22,headertag); + header[0x30]=40; + if (!faceA) { + faceA=&emptyface; + faceA->edsk_filename=TxtStrDup(faceB->edsk_filename); + } +#if TRACE_EDSK + printf("deleting [%s]\n",faceA->edsk_filename); +#endif + FileRemoveIfExists(faceA->edsk_filename); + + if (faceB!=NULL) header[0x31]=2; else header[0x31]=1; + for (i=0;iedsk_filename,(char *)header,256); + + /* écriture des pistes */ + for (t=0;t<40;t++) { + strcpy((char *)trackblock,"Track-Info\r\n"); + trackblock[0x10]=t; + trackblock[0x11]=0; + trackblock[0x14]=2; + trackblock[0x15]=9; + trackblock[0x16]=0x4E; + trackblock[0x17]=0xE5; + i=0; + while (1) { + trackblock[0x18+i*8+0]=trackblock[0x10]; + trackblock[0x18+i*8+1]=trackblock[0x11]; + trackblock[0x18+i*8+2]=(i>>1)+0xC1; +#if TRACE_EDSK + if (t<3) printf("%02X ",trackblock[0x18+i*8+2]); +#endif + trackblock[0x18+i*8+3]=2; + trackblock[0x18+i*8+4]=0; + trackblock[0x18+i*8+5]=0; + trackblock[0x18+i*8+6]=0; + trackblock[0x18+i*8+7]=2; + i++; + if (i==9) break; + /* interleave */ + trackblock[0x18+i*8+0]=trackblock[0x10]; + trackblock[0x18+i*8+1]=trackblock[0x11]; + trackblock[0x18+i*8+2]=(i>>1)+0xC6; /* start at C6 */ +#if TRACE_EDSK + if (t<3) printf("%02X ",trackblock[0x18+i*8+2]); +#endif + trackblock[0x18+i*8+3]=2; + trackblock[0x18+i*8+4]=0; + trackblock[0x18+i*8+5]=0; + trackblock[0x18+i*8+6]=0; + trackblock[0x18+i*8+7]=2; + i++; + } +#if TRACE_EDSK + if (t<3) printf("\n"); else if (t==3) printf("...\n"); +#endif + /* écriture du track info */ + FileWriteBinary(faceA->edsk_filename,(char *)trackblock,256); + + + /* il faut convertir les blocs logiques en secteurs physiques ET entrelacés */ + idblock=t*9/2; + blockoffset=((t*9)%2)*512; + + /* le premier secteur de la piste est à cheval sur le bloc logique une fois sur deux */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock][0]+blockoffset,512); /* C1 */ + if (!blockoffset) { + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+2][0]+512,512); /* C6 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+0][0]+512,512); /* C2 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+3][0]+0,512); /* C7 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+1][0]+0,512); /* C3 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+3][0]+512,512); /* C8 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+1][0]+512,512); /* C4 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+4][0]+0,512); /* C9 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+2][0]+0,512); /* C5 */ + } else { + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+3][0]+0,512); /* C6 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+1][0]+0,512); /* C2 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+3][0]+512,512); /* C7 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+1][0]+512,512); /* C3 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+4][0]+0,512); /* C8 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+2][0]+0,512); /* C4 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+4][0]+512,512); /* C9 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+2][0]+512,512); /* C5 */ + } + + /* @@TODO ça semble un peu foireux comme procédé */ + if (faceB) { +#if TRACE_EDSK + printf("writing EDSK face B /!\\ probably NOT WORKING !!!\n"); +#endif + trackblock[0x11]=1; + for (i=0;i<9;i++) { + trackblock[0x18+i*8+0]=trackblock[0x10]; + trackblock[0x18+i*8+1]=trackblock[0x11]; + } + /* écriture du track info */ + FileWriteBinary(faceB->edsk_filename,(char *)trackblock,256); + /* écriture des secteurs */ + idblock=t*9/2; + blockoffset=((t*9)%2)*512; + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock][0]+blockoffset,512); + if (!blockoffset) { + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+2][0]+512,512); /* C6 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+0][0]+512,512); /* C2 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+3][0]+0,512); /* C7 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+1][0]+0,512); /* C3 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+3][0]+512,512); /* C8 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+1][0]+512,512); /* C4 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+4][0]+0,512); /* C9 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+2][0]+0,512); /* C5 */ + } else { + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+3][0]+0,512); /* C6 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+1][0]+0,512); /* C2 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+3][0]+512,512); /* C7 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+1][0]+512,512); /* C3 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+4][0]+0,512); /* C8 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+2][0]+0,512); /* C4 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+4][0]+512,512); /* C9 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+2][0]+512,512); /* C5 */ + } + } + } + FileWriteBinaryClose(faceA->edsk_filename); + rasm_printf(ae,KIO"Write edsk file %s\n",faceA->edsk_filename); +} +void EDSK_write(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "EDSK_write" + + struct s_edsk_wrapper *faceA,*faceB; + int i,j; + + + /* on passe en revue toutes les structs */ + for (i=0;inbedskwrapper;i++) { + /* already done */ + if (ae->edsk_wrapper[i].face==-1) continue; + + switch (ae->edsk_wrapper[i].face) { + default: + case 0:faceA=&ae->edsk_wrapper[i];faceB=NULL;break; + case 1:faceA=NULL;faceB=&ae->edsk_wrapper[i];break; + } + /* doit-on fusionner avec une autre face? */ + for (j=i+1;jnbedskwrapper;j++) { + if (!strcmp(ae->edsk_wrapper[i].edsk_filename,ae->edsk_wrapper[j].edsk_filename)) { + /* found another face for the floppy */ + switch (ae->edsk_wrapper[j].face) { + default: + case 0:faceA=&ae->edsk_wrapper[j];break; + case 1:faceB=&ae->edsk_wrapper[j];break; + } + } + } + EDSK_write_file(ae,faceA,faceB); + } +} + +/* CDT output code / courtesy of CNG */ +void update11(unsigned char *head,int n,int is1st,int islast,int l, int fileload) +{ + head[0x10]=n; + head[0x11]=islast?-1:0; + head[0x13]=l; + head[0x14]=l>>8; + head[0x15]=fileload; + head[0x16]=fileload>>8; + head[0x17]=is1st?-1:0; +} +#define fputcc(x,y) { fputc((x),y); fputc((x)>>8,y); } +#define fputccc(x,y) { fputc((x),y); fputc((x)>>8,y); fputc((x)>>16,y); } +void record11(char *filename,unsigned char *t,int first,int l,int p, int flag_bb, int flag_b) +{ + FILE *fo; + #ifdef OS_WIN + fo=FileOpen(filename,"w"); + #else + fo=FileOpen(filename,"a+"); + #endif + + /* almost legacy */ + fputc(0x11,fo); + fputcc(flag_bb,fo); + fputcc(flag_b,fo); + fputcc(flag_b,fo); + fputcc(flag_b,fo); + fputcc(flag_bb,fo); + //fputcc(flag_o,fo); + fputcc(4096,fo); // 4K block + fputc(8,fo); + fputcc(p,fo); + p=1+(((l+255)/256)*258)+4; //flag_z; + fputccc(p,fo); + fputc(first,fo); + p=0; + while (l>0) + { + int crc16=0xFFFF; + fwrite(t+p,1,256,fo); + first=256; + while (first--) { + // early CRC-16-CCITT as used by Amstrad + int xor8=(t[p++]<<8)+1; + while (xor8&0xFF) + { + if ((xor8^crc16)&0x8000) + crc16=((crc16^0x0810)<<1)+1; + else + crc16<<=1; + xor8<<=1; + } + } + crc16=~crc16; + fputc(crc16>>8,fo); // HI FIRST, + fputc(crc16,fo); // AND LO NEXT! + l-=256; + } + l=4; //flag_z; + while (l--) + fputc(255,fo); +} + +void __output_CDT(struct s_assenv *ae, char *tapefilename,char *filename,char *mydata,int size, int offset, int run) +{ + unsigned char *AmsdosHeader; + unsigned char head[256]; + char TZX_header[14]; + int wrksize,fileload,nbblock=0; + unsigned char body[65536+128]; + int flag_h=2560, flag_p=10240, flag_bb, flag_b=1000,i,j,k; + + FileRemoveIfExists(tapefilename); // pas de append pour le moment + + memcpy(TZX_header,"ZXTape!\032\001\000\040\000\012",13); + FileWriteBinary(tapefilename,(char *)TZX_header,13); + + AmsdosHeader=MakeAMSDOSHeader(run,offset,offset+size,MakeAMSDOS_name(ae,filename)); + memcpy(body,AmsdosHeader,128); + wrksize=size; + + memset(head,0,16); + strcpy(head,MakeAMSDOS_name(ae,filename)); + head[0x12]=body[0x12]; + head[0x18]=body[0x40]; + head[0x19]=body[0x41]; + head[0x1A]=body[0x1A]; + head[0x1B]=body[0x1B]; + fileload=body[0x15]+body[0x16]*256; + flag_b=(3500000/3+flag_b/2)/flag_b; + flag_bb=flag_b*2; + memcpy(body,mydata,size); + + if (wrksize>0x800) { + update11(head,j=1,1,0,0x800,fileload); // FIRST BLOCK + record11(tapefilename,head,44,28,16,flag_bb,flag_b); + record11(tapefilename,body,22,0x800,flag_h,flag_bb,flag_b); + k=wrksize-0x800; + i=0x800; + nbblock=1; + while (k>0x800) { + fileload+=0x800; + update11(head,++j,0,0,0x800,fileload); // MID BLOCK + record11(tapefilename,head,44,28,16,flag_bb,flag_b); + record11(tapefilename,body+i,22,0x800,flag_h,flag_bb,flag_b); + k-=0x800; + i+=0x800; + nbblock++; + } + nbblock++; + fileload+=0x800; + update11(head,++j,0,1,k,fileload); // LAST BLOCK + record11(tapefilename,head,44,28,16,flag_bb,flag_b); + record11(tapefilename,body+i,22,k,flag_p,flag_bb,flag_b); + } else { + update11(head,1,1,1,wrksize,fileload); // SINGLE BLOCK + record11(tapefilename,head,44,28,16,flag_bb,flag_b); + record11(tapefilename,body,22,wrksize,flag_p,flag_bb,flag_b); + nbblock=1; + } + FileWriteBinaryClose(tapefilename); + rasm_printf(ae,KIO"Write tape file %s (%d block%s) run=#%04X\n",tapefilename,nbblock,nbblock>1?"s":"",run); +} + + + +void PopAllSave(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "PopAllSave" + + unsigned char *AmsdosHeader; + char *dskfilename; + char *filename; + int offset,size,run; + int i,is,erreur=0,touched; + + for (is=0;isnbsave;is++) { + /* avoid quotes */ + if (!ae->save[is].iw) filename=ae->save[is].filename; else { + filename=ae->wl[ae->save[is].iw].w; + filename[strlen(filename)-1]=0; + filename=TxtStrDup(filename+1); + /* crappy POST translate tags! => deprecated! + filename=TranslateTag(ae,filename,&touched,1,E_TAGOPTION_REMOVESPACE); */ + } + +#if TRACE_EDSK + printf("woff=[%s](%d) wsize=[%s](%d)\n",ae->wl[ae->save[is].ioffset].w,ae->save[is].ioffset,ae->wl[ae->save[is].isize].w,ae->save[is].isize); +#endif + + ae->idx=ae->save[is].ioffset; /* exp hack */ + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + offset=RoundComputeExpression(ae,ae->wl[ae->idx].w,0,0,0); + + ae->idx=ae->save[is].isize; /* exp hack */ + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + size=RoundComputeExpression(ae,ae->wl[ae->idx].w,0,0,0); + + ae->idx=ae->save[is].irun; /* exp hack */ + if (ae->idx) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + run=RoundComputeExpression(ae,ae->wl[ae->idx].w,0,0,0); + } else { + run=offset; + } + + if (size<1 || size>65536) { + MakeError(ae,NULL,0,"cannot save [%s] as the size is invalid!\n",filename); + MemFree(filename); + continue; + } + if (offset<0 || offset>65535) { + MakeError(ae,NULL,0,"cannot save [%s] as the offset is invalid!\n",filename); + MemFree(filename); + continue; + } + if (offset+size>65536) { + MakeError(ae,NULL,0,"cannot save [%s] as the offset+size will be out of bounds!\n",filename); + MemFree(filename); + continue; + } + /* DSK management */ + if (ae->save[is].dsk) { + if (ae->save[is].iwdskname!=-1) { + /* obligé de dupliquer à cause du reuse */ + dskfilename=TxtStrDup(ae->wl[ae->save[is].iwdskname].w); + dskfilename[strlen(dskfilename)-1]=0; + if (!EDSK_addfile(ae,dskfilename+1,ae->save[is].face,filename,ae->mem[ae->save[is].ibank]+offset,size,offset,run)) { + erreur++; + //break; + } + MemFree(dskfilename); + } + } else if (ae->save[is].tape) { + char *tapefilename; + + if (ae->save[is].iwdskname>0) { + tapefilename=ae->wl[ae->save[is].iwdskname].w; + tapefilename[strlen(tapefilename)-1]=0; + tapefilename=TxtStrDup(tapefilename+1); + } else { + tapefilename=TxtStrDup("rasmoutput.cdt"); + } + + __output_CDT(ae,tapefilename,filename,(char*)ae->mem[ae->save[is].ibank]+offset,size,offset,run); + } else { + /* output file on filesystem */ + rasm_printf(ae,KIO"Write binary file %s (%d byte%s)\n",filename,size,size>1?"s":""); + FileRemoveIfExists(filename); + if (ae->save[is].amsdos) { + AmsdosHeader=MakeAMSDOSHeader(run,offset,offset+size,MakeAMSDOS_name(ae,filename)); + FileWriteBinary(filename,(char *)AmsdosHeader,128); + } else if (ae->save[is].hobeta) { + // HOBETA header is 17 bytes long so i reuse Amsdos buffer and name cleaning + AmsdosHeader=MakeHobetaHeader(offset,offset+size,MakeAMSDOS_name(ae,filename)); + FileWriteBinary(filename,(char *)AmsdosHeader,17); + } + FileWriteBinary(filename,(char*)ae->mem[ae->save[is].ibank]+offset,size); + FileWriteBinaryClose(filename); + } + MemFree(filename); + } + if (!erreur) EDSK_write(ae); + + for (i=0;inbedskwrapper;i++) { + MemFree(ae->edsk_wrapper[i].edsk_filename); + } + if (ae->maxedskwrapper) MemFree(ae->edsk_wrapper); + + if (ae->nbsave) { + MemFree(ae->save); + } +} + +void PopAllExpression(struct s_assenv *ae, int crunched_zone) +{ + #undef FUNC + #define FUNC "PopAllExpression" + + static int first=1; + double v; + long r; + int i,mapflag=0; + unsigned char *mem; + char *expr; + + /* pop all expressions BUT thoses who where already computed (in crunched blocks) */ + + /* calcul des labels et expressions en zone crunch (et locale?) + les labels doivent pointer: + - une valeur absolue (numerique ou variable calculee) -> completement transparent + - un label dans la meme zone de crunch -> label->lz=1 && verif de la zone crunch + - un label hors zone crunch MAIS avant toute zone de crunch de la bank destination (!label->lz) + + idealement on doit tolerer les adresses situees apres le crunch dans une autre ORG zone! + + on utilise ae->stage pour créer un état intermédiaire dans le ComputeExpressionCore + */ + if (crunched_zone>=0) { + ae->stage=1; + } else { + /* on rescanne tout pour combler les trous */ + ae->stage=2; + first=1; + } + + for (i=first;iie;i++) { + /* first compute only crunched expression (0,1,2,3,...) then intermediates and (-1) at the end */ + if (crunched_zone>=0) { + /* jump over previous crunched or non-crunched zones */ + if (ae->expression[i].lzexpression[i].lz>crunched_zone) { + first=i; + break; + } + } else { + if (ae->expression[i].lz>=0) continue; + } + + mem=ae->mem[ae->expression[i].ibank]; + + if (ae->expression[i].reference) { + expr=ae->expression[i].reference; + } else { + expr=ae->wl[ae->expression[i].iw].w; + } + +#if TRACE_POPEXPR + printf("PopAll (%d) expr=[%s] ptr=%X outputadr=%X\n",crunched_zone,expr,ae->expression[i].ptr,ae->expression[i].wptr); +#endif + if (ae->nexternal) { + int iex,jex; + mapflag=0; + for (iex=0;iexnexternal;iex++) { + for (jex=0;jexexternal[iex].nmapping;jex++) { + if (ae->expression[i].wptr==ae->external[iex].mapping[jex].ptr) { +#if TRACE_POPEXPR + printf("MAPPING [%s] adr=%d size=%d\n",ae->external[iex].name,ae->expression[i].wptr,ae->external[iex].mapping[jex].size); +#endif + mapflag=1; + break; + } + } + } + } + v=ComputeExpressionCore(ae,expr,ae->expression[i].ptr,i); + r=(long)floor(v+ae->rough); +#if TRACE_POPEXPR + printf("resultat du compute=>%ld (%lf + rough=%lf)\n",r,v,ae->rough); +#endif + + switch (ae->expression[i].zetype) { + case E_EXPRESSION_J8: + r=r-ae->expression[i].ptr-2; + if (r<-128 || r>127) { + MakeError(ae,GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,"relative offset %d too far [%s]\n",r,ae->wl[ae->expression[i].iw].w); + } + mem[ae->expression[i].wptr]=(unsigned char)r; + break; + case E_EXPRESSION_IV81: + /* for enhanced 16bits instructions */ + r++; + case E_EXPRESSION_0V8: + case E_EXPRESSION_IV8: + case E_EXPRESSION_3V8: + case E_EXPRESSION_V8: + if (r>255 || r<-128) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: truncating value #%X to #%X\n",GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,r,r&0xFF); + if (ae->erronwarn) MaxError(ae); + } + } + mem[ae->expression[i].wptr]=(unsigned char)r; + break; + case E_EXPRESSION_J16: + case E_EXPRESSION_J16C: + /* buildobj */ + if (ae->buildobj && !mapflag) { + struct s_external_mapping relocation; + //printf("RELOCATION %04X\n",ae->expression[i].wptr); + relocation.iorgzone=ae->expression[i].ibank; // bank hack + relocation.ptr=ae->expression[i].wptr; + relocation.size=2; + relocation.value=r&0xFFFF; + ObjectArrayAddDynamicValueConcat((void**)&ae->relocation,&ae->nrelocation,&ae->mrelocation,&relocation,sizeof(relocation)); + } + case E_EXPRESSION_IV16: + case E_EXPRESSION_V16: + case E_EXPRESSION_0V16: + if (r>65535 || r<-32768) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: truncating value #%X to #%X\n",GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,r,r&0xFFFF); + if (ae->erronwarn) MaxError(ae); + } + } + mem[ae->expression[i].wptr]=(unsigned char)r&0xFF; + mem[ae->expression[i].wptr+1]=(unsigned char)((r&0xFF00)>>8); + break; + case E_EXPRESSION_0V32: + /* meaningless in 32 bits architecture... */ + if (v>4294967295 || v<-2147483648) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: truncating value\n",GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l); + if (ae->erronwarn) MaxError(ae); + } + } + mem[ae->expression[i].wptr]=(unsigned char)r&0xFF; + mem[ae->expression[i].wptr+1]=(unsigned char)((r>>8)&0xFF); + mem[ae->expression[i].wptr+2]=(unsigned char)((r>>16)&0xFF); + mem[ae->expression[i].wptr+3]=(unsigned char)((r>>24)&0xFF); + break; + case E_EXPRESSION_0VR: + /* convert v double value to Amstrad REAL */ + memcpy(&mem[ae->expression[i].wptr],__internal_MakeAmsdosREAL(ae,v,i),5); + break; + case E_EXPRESSION_0VRMike: + /* convert v double value to Microsoft 40bits REAL */ + memcpy(&mem[ae->expression[i].wptr],__internal_MakeRosoftREAL(ae,v,i),5); + break; + case E_EXPRESSION_IM: + switch (r) { + case 0x00:mem[ae->expression[i].wptr]=0x46;break; + case 0x01:mem[ae->expression[i].wptr]=0x56;break; + case 0x02:mem[ae->expression[i].wptr]=0x5E;break; + default: + MakeError(ae,GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,"IM 0,1 or 2 only\n"); + mem[ae->expression[i].wptr]=0; + } + break; + case E_EXPRESSION_RST: + switch (r) { + case 0x00:mem[ae->expression[i].wptr]=0xC7;break; + case 0x08:mem[ae->expression[i].wptr]=0xCF;break; + case 0x10:mem[ae->expression[i].wptr]=0xD7;break; + case 0x18:mem[ae->expression[i].wptr]=0xDF;break; + case 0x20:mem[ae->expression[i].wptr]=0xE7;break; + case 0x28:mem[ae->expression[i].wptr]=0xEF;break; + case 0x30:mem[ae->expression[i].wptr]=0xF7;break; + case 0x38:mem[ae->expression[i].wptr]=0xFF;break; + default: + MakeError(ae,GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,"RST #0,#8,#10,#18,#20,#28,#30,#38 only\n"); + mem[ae->expression[i].wptr]=0; + } + break; + case E_EXPRESSION_RUN: + if (r<0 || r>65535) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: run address truncated from %X to %X\n",GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,r,r&0xFFFF); + if (ae->erronwarn) MaxError(ae); + } + } + ae->snapshot.registers.LPC=r&0xFF; + ae->snapshot.registers.HPC=(r>>8)&0xFF; + break; + case E_EXPRESSION_ZXRUN: + if (r<0 || r>65535) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: run address truncated from %X to %X\n",GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,r,r&0xFFFF); + if (ae->erronwarn) MaxError(ae); + } + } + ae->zxsnapshot.run=r&0xFFFF; + break; + case E_EXPRESSION_ZXSTACK: + if (r<0 || r>65535) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: stack address truncated from %X to %X\n",GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,r,r&0xFFFF); + if (ae->erronwarn) MaxError(ae); + } + } + ae->zxsnapshot.stack=r&0xFFFF; + break; + case E_EXPRESSION_BRS: + if (r>=0 && r<8) { + mem[ae->expression[i].wptr]+=r*8; + } else { + MakeError(ae,GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,"SET,RES,BIT shift value from 0 to 7 only\n"); + } + break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"FATAL - unknown expression type\n"); + FreeAssenv(ae);exit(-8); + } + } +} + +void InsertLabelToTree(struct s_assenv *ae, struct s_label *label) +{ + #undef FUNC + #define FUNC "InsertLabelToTree" + + struct s_crclabel_tree *curlabeltree; + int radix,dek=32; + + curlabeltree=&ae->labeltree; + while (dek) { + dek=dek-8; + radix=(label->crc>>dek)&0xFF; + if (curlabeltree->radix[radix]) { + curlabeltree=curlabeltree->radix[radix]; + } else { + curlabeltree->radix[radix]=MemMalloc(sizeof(struct s_crclabel_tree)); + curlabeltree=curlabeltree->radix[radix]; + memset(curlabeltree,0,sizeof(struct s_crclabel_tree)); + } + } + ObjectArrayAddDynamicValueConcat((void**)&curlabeltree->label,&curlabeltree->nlabel,&curlabeltree->mlabel,&label[0],sizeof(struct s_label)); +} + +/* use by structure mechanism and label import to add fake labels */ +void PushLabelLight(struct s_assenv *ae, struct s_label *curlabel) { + #undef FUNC + #define FUNC "PushLabelLight" + + struct s_label *searched_label; + + /* PushLabel light */ + if ((searched_label=SearchLabel(ae,curlabel->name,curlabel->crc))!=NULL) { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"%s caused duplicate label [%s]\n",ae->idx?"Structure insertion":"Label import",curlabel->name); + MemFree(curlabel->name); + } else { + curlabel->backidx=ae->il; + curlabel->autorise_export=ae->autorise_export&(!ae->getstruct); + ObjectArrayAddDynamicValueConcat((void **)&ae->label,&ae->il,&ae->ml,curlabel,sizeof(struct s_label)); + InsertLabelToTree(ae,curlabel); + } +} +void PushLabel(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "PushLabel" + + struct s_label curlabel={0},*searched_label; + int i; + /* label with counters */ + char *varbuffer; + int tagcount=0; + int touched; + +#if TRACE_LABEL + printf("check label [%s]\n",ae->wl[ae->idx].w); +#endif + if (ae->AutomateValidLabelFirst[(int)ae->wl[ae->idx].w[0]&0xFF]) { + for (i=1;ae->wl[ae->idx].w[i];i++) { + if (ae->wl[ae->idx].w[i]=='{') tagcount++; else if (ae->wl[ae->idx].w[i]=='}') tagcount--; + if (!tagcount) { + if (!ae->AutomateValidLabel[(int)ae->wl[ae->idx].w[i]&0xFF]) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid char in label declaration (%c)\n",ae->wl[ae->idx].w[i]); + return; + } + } + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid first char in label declaration (%c)\n",ae->wl[ae->idx].w[0]); + return; + } + + switch (i) { + case 1: + switch (ae->wl[ae->idx].w[0]) { + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'H': + case 'L': + case 'I': + case 'R': + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use reserved word [%s] for label\n",ae->wl[ae->idx].w); + return; + default:break; + } + break; + case 2: + if (strcmp(ae->wl[ae->idx].w,"AF")==0 || strcmp(ae->wl[ae->idx].w,"BC")==0 || strcmp(ae->wl[ae->idx].w,"DE")==0 || strcmp(ae->wl[ae->idx].w,"HL")==0 || + strcmp(ae->wl[ae->idx].w,"IX")==0 || strcmp(ae->wl[ae->idx].w,"IY")==0 || strcmp(ae->wl[ae->idx].w,"SP")==0 || + strcmp(ae->wl[ae->idx].w,"LX")==0 || strcmp(ae->wl[ae->idx].w,"HX")==0 || strcmp(ae->wl[ae->idx].w,"XL")==0 || strcmp(ae->wl[ae->idx].w,"XH")==0 || + strcmp(ae->wl[ae->idx].w,"LY")==0 || strcmp(ae->wl[ae->idx].w,"HY")==0 || strcmp(ae->wl[ae->idx].w,"YL")==0 || strcmp(ae->wl[ae->idx].w,"YH")==0) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use reserved word [%s] for label\n",ae->wl[ae->idx].w); + return; + } + break; + case 3: + if (strcmp(ae->wl[ae->idx].w,"IXL")==0 || strcmp(ae->wl[ae->idx].w,"IYL")==0 || strcmp(ae->wl[ae->idx].w,"IXH")==0 || strcmp(ae->wl[ae->idx].w,"IYH")==0) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use reserved word [%s] for label\n",ae->wl[ae->idx].w); + return; + } + break; + case 4: + if (strcmp(ae->wl[ae->idx].w,"VOID")==0) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use reserved word [%s] for label\n",ae->wl[ae->idx].w); + return; + } + default:break; + } + + /******************************************************* + v a r i a b l e s i n l a b e l n a m e + + -- varbuffer is always allocated -- + *******************************************************/ + varbuffer=TranslateTag(ae,TxtStrDup(ae->wl[ae->idx].w),&touched,1,E_TAGOPTION_NONE); // on se moque du touched ici => varbuffer toujours "new" +#if TRACE_LABEL + printf("label after translation [%s]\n",varbuffer); +#endif + /************************************************** + s t r u c t u r e d e c l a r a t i o n + **************************************************/ + if (ae->getstruct) { + struct s_rasmstructfield rasmstructfield={0}; +#if TRACE_LABEL + printf("label used for structs! [%s]\n",varbuffer); +#endif + if (varbuffer[0]=='@') { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Please no local label in a struct [%s]\n",ae->wl[ae->idx].w); + MemFree(varbuffer); + return; + } + /* copy label+offset in the structure */ + rasmstructfield.name=varbuffer; + rasmstructfield.offset=ae->codeadr; + ObjectArrayAddDynamicValueConcat((void **)&ae->rasmstruct[ae->irasmstruct-1].rasmstructfield, + &ae->rasmstruct[ae->irasmstruct-1].irasmstructfield,&ae->rasmstruct[ae->irasmstruct-1].mrasmstructfield, + &rasmstructfield,sizeof(rasmstructfield)); + /* label is structname+field */ + curlabel.name=MemMalloc(strlen(ae->rasmstruct[ae->irasmstruct-1].name)+strlen(varbuffer)+2); + sprintf(curlabel.name,"%s.%s",ae->rasmstruct[ae->irasmstruct-1].name,varbuffer); + curlabel.iw=-1; + /* legacy */ + curlabel.crc=GetCRC(curlabel.name); + curlabel.ptr=ae->codeadr; +#if TRACE_STRUCT + printf("pushLabel (struct) [%X] [%s]\n",curlabel.ptr,curlabel.name); +#endif + } else { + /************************************************** + l a b e l s + **************************************************/ + /* labels locaux */ + if (varbuffer[0]=='@' && (ae->ir || ae->iw || ae->imacro)) { +#if TRACE_LABEL + printf("PUSH LOCAL\n"); +#endif + curlabel.iw=-1; + curlabel.local=1; + curlabel.name=MakeLocalLabel(ae,varbuffer,NULL); MemFree(varbuffer); + curlabel.crc=GetCRC(curlabel.name); + + /* local labels ALSO set new reference */ + if (ae->lastglobalalloc) { +//printf("push LOCAL is freeing lastgloballabel\n"); + MemFree(ae->lastgloballabel); + } + ae->lastgloballabel=TxtStrDup(curlabel.name); + ae->lastgloballabellen=strlen(ae->lastgloballabel); + ae->lastglobalalloc=1; +//printf("push LOCAL as reference [%d] for proximity label -> [%s]\n",im, ae->lastgloballabel); + + } else { +#if TRACE_LABEL + printf("PUSH GLOBAL or PROXIMITY\n"); +#endif + switch (varbuffer[0]) { + case '.': + if (ae->dams) { + /* old Dams style declaration (remove the dot) */ + i=0; + do { + varbuffer[i]=varbuffer[i+1]; + i++; + } while (varbuffer[i]!=0); + + curlabel.iw=-1; + curlabel.name=varbuffer; + curlabel.crc=GetCRC(curlabel.name); + } else { + /* proximity labels */ + if (ae->lastgloballabel) { + curlabel.name=MemMalloc(strlen(varbuffer)+1+ae->lastgloballabellen); + sprintf(curlabel.name,"%s%s",ae->lastgloballabel,varbuffer); + MemFree(varbuffer); + curlabel.iw=-1; + curlabel.crc=GetCRC(curlabel.name); +#if TRACE_LABEL +printf("PUSH PROXIMITY label that may be exported [%s]->[%s]\n",ae->wl[ae->idx].w,curlabel.name); +#endif + } else { +#if TRACE_LABEL +printf("PUSH Orphan PROXIMITY label that cannot be exported [%s]->[%s]\n",ae->wl[ae->idx].w,curlabel.name); +#endif + + curlabel.iw=-1; + curlabel.name=varbuffer; + curlabel.crc=GetCRC(varbuffer); + } + } + break; + default: +#if TRACE_LABEL + printf("PUSH => GLOBAL [%s]\n",varbuffer); +#endif + curlabel.iw=-1; + curlabel.name=varbuffer; + curlabel.crc=GetCRC(varbuffer); + + /* global labels set new reference */ + if (ae->lastglobalalloc) MemFree(ae->lastgloballabel); + ae->lastgloballabel=TxtStrDup(curlabel.name); + ae->lastgloballabellen=strlen(curlabel.name); + ae->lastglobalalloc=1; + break; + } + + + /* this stage varbuffer maybe already freed or used */ + if (curlabel.name[0]!='@' && ae->module && ae->modulen) { + char *newlabelname; + + newlabelname=MemMalloc(strlen(curlabel.name)+ae->modulen+2); + strcpy(newlabelname,ae->module); + strcat(newlabelname,ae->module_separator); + strcat(newlabelname,curlabel.name); + MemFree(curlabel.name); + curlabel.name=newlabelname; + curlabel.crc=GetCRC(curlabel.name); + //curlabel.iw=-1; => deja mis depuis longtemps + } +#if TRACE_LABEL + if (curlabel.name[0]!='@') printf("PUSH => ADD MODULE [%s] => [%s]\n",ae->module?ae->module:"(null)",curlabel.name); + else printf("PUSH => NO MODULE for local label\n"); +#endif + + /* contrôle dico uniquement avec des labels non locaux */ + if (SearchDico(ae,curlabel.name,curlabel.crc)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"cannot create label [%s] as there is already a variable with the same name\n",curlabel.name); + return; + } + if(SearchAlias(ae,curlabel.crc,curlabel.name)!=-1) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"cannot create label [%s] as there is already an alias with the same name\n",curlabel.name); + return; + } + } + curlabel.ptr=ae->codeadr; + curlabel.ibank=ae->activebank; + curlabel.iorgzone=ae->io-1; + curlabel.lz=ae->lz; + } + + if ((searched_label=SearchLabel(ae,curlabel.name,curlabel.crc))!=NULL) { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"Duplicate label [%s] - previously defined in [%s:%d]\n",curlabel.name,ae->filename[searched_label->fileidx],searched_label->fileline); + MemFree(curlabel.name); + } else { +//printf("PushLabel(%s) name=%s crc=%X lz=%d\n",curlabel.name,curlabel.name?curlabel.name:"null",curlabel.crc,curlabel.lz); + curlabel.fileidx=ae->wl[ae->idx].ifile; + curlabel.fileline=ae->wl[ae->idx].l; + curlabel.autorise_export=ae->autorise_export&(!ae->getstruct); + curlabel.backidx=ae->il; + ObjectArrayAddDynamicValueConcat((void **)&ae->label,&ae->il,&ae->ml,&curlabel,sizeof(curlabel)); + InsertLabelToTree(ae,&curlabel); + } + +} + + +unsigned char *EncodeSnapshotRLE(unsigned char *memin, int *lenout) { + #undef FUNC + #define FUNC "EncodeSnapshotRLE" + + int i,cpt,idx=0; + unsigned char *memout; + + memout=MemMalloc(65536*2); + + for (i=0;i<65536;) { + + for (cpt=1;cpt<255 && i+cpt<65536;cpt++) if (memin[i]!=memin[i+cpt]) break; + + if (cpt>=3 || memin[i]==0xE5) { + memout[idx++]=0xE5; + memout[idx++]=cpt; + memout[idx++]=memin[i]; + i+=cpt; + } else { + memout[idx++]=memin[i++]; + } + } + if (lenout) *lenout=idx; + if (idx<65536) return memout; + + MemFree(memout); + *lenout=65536; // means cannot pack + return NULL; + +} + + + +#undef FUNC +#define FUNC "Instruction CORE" + +void _IN(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + if (strcmp(ae->wl[ae->idx+2].w,"(C)")==0) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_0: + case CRC_F:___output(ae,0xED);___output(ae,0x70);ae->nop+=4;ae->tick+=12;break; + case CRC_A:___output(ae,0xED);___output(ae,0x78);ae->nop+=4;ae->tick+=12;break; + case CRC_B:___output(ae,0xED);___output(ae,0x40);ae->nop+=4;ae->tick+=12;break; + case CRC_C:___output(ae,0xED);___output(ae,0x48);ae->nop+=4;ae->tick+=12;break; + case CRC_D:___output(ae,0xED);___output(ae,0x50);ae->nop+=4;ae->tick+=12;break; + case CRC_E:___output(ae,0xED);___output(ae,0x58);ae->nop+=4;ae->tick+=12;break; + case CRC_H:___output(ae,0xED);___output(ae,0x60);ae->nop+=4;ae->tick+=12;break; + case CRC_L:___output(ae,0xED);___output(ae,0x68);ae->nop+=4;ae->tick+=12;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is IN [0,F,A,B,C,D,E,H,L],(C)\n"); + } + } else if (strcmp(ae->wl[ae->idx+1].w,"A")==0 && StringIsMem(ae->wl[ae->idx+2].w)) { + ___output(ae,0xDB); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=3; + ae->tick+=11; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IN [0,F,A,B,C,D,E,H,L],(C) or IN A,(n) only\n"); + } + ae->idx+=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IN [0,F,A,B,C,D,E,H,L],(C) or IN A,(n) only\n"); + } +} + +void _OUT(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + if (strcmp(ae->wl[ae->idx+1].w,"(C)")==0) { + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_0:___output(ae,0xED);___output(ae,0x71);ae->nop+=4;ae->tick+=12;break; + case CRC_A:___output(ae,0xED);___output(ae,0x79);ae->nop+=4;ae->tick+=12;break; + case CRC_B:___output(ae,0xED);___output(ae,0x41);ae->nop+=4;ae->tick+=12;break; + case CRC_C:___output(ae,0xED);___output(ae,0x49);ae->nop+=4;ae->tick+=12;break; + case CRC_D:___output(ae,0xED);___output(ae,0x51);ae->nop+=4;ae->tick+=12;break; + case CRC_E:___output(ae,0xED);___output(ae,0x59);ae->nop+=4;ae->tick+=12;break; + case CRC_H:___output(ae,0xED);___output(ae,0x61);ae->nop+=4;ae->tick+=12;break; + case CRC_L:___output(ae,0xED);___output(ae,0x69);ae->nop+=4;ae->tick+=12;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is OUT (C),[0,A,B,C,D,E,H,L]\n"); + } + } else if (strcmp(ae->wl[ae->idx+2].w,"A")==0 && StringIsMem(ae->wl[ae->idx+1].w)) { + ___output(ae,0xD3); + PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); + ae->nop+=3; + ae->tick+=11; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"OUT (C),[0,A,B,C,D,E,H,L] or OUT (n),A only\n"); + } + ae->idx+=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"OUT (C),[0,A,B,C,D,E,H,L] or OUT (n),A only\n"); + } +} + +void _EX(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_HL: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_DE:___output(ae,0xEB);ae->nop+=1;ae->tick+=4;break; + case CRC_MSP:___output(ae,0xE3);ae->nop+=6;ae->tick+=19;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is EX HL,[(SP),DE]\n"); + } + break; + case CRC_AF: + if (strcmp(ae->wl[ae->idx+2].w,"AF'")==0) { + ___output(ae,0x08);ae->nop+=1;ae->tick+=4; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is EX AF,AF'\n"); + } + break; + case CRC_MSP: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_HL:___output(ae,0xE3);ae->nop+=6;ae->tick+=19;break; + case CRC_IX:___output(ae,0xDD);___output(ae,0xE3);ae->nop+=7;ae->tick+=23;break; + case CRC_IY:___output(ae,0xFD);___output(ae,0xE3);ae->nop+=7;ae->tick+=23;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is EX (SP),[HL,IX,IY]\n"); + } + break; + case CRC_DE: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_HL:___output(ae,0xEB);ae->nop+=1;ae->tick+=4;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is EX DE,HL\n"); + } + break; + case CRC_IX: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_MSP:___output(ae,0xDD);___output(ae,0xE3);ae->nop+=7;ae->tick+=23;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is EX IX,(SP)\n"); + } + break; + case CRC_IY: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_MSP:___output(ae,0xFD);___output(ae,0xE3);ae->nop+=7;ae->tick+=23;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is EX IY,(SP)\n"); + } + break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is EX [AF,DE,HL,(SP),IX,IY],reg16\n"); + } + ae->idx+=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use EX reg16,[DE|(SP)]\n"); + } +} + +void _SBC(struct s_assenv *ae) { + if ((!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) || ((!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) && strcmp(ae->wl[ae->idx+1].w,"A")==0)) { + if (!ae->wl[ae->idx+1].t) ae->idx++; + /* do implicit A */ + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_A:___output(ae,0x9F);ae->nop+=1;ae->tick+=4;break; + case CRC_MHL:___output(ae,0x9E);ae->nop+=2;ae->tick+=7;break; + case CRC_B:___output(ae,0x98);ae->nop+=1;ae->tick+=4;break; + case CRC_C:___output(ae,0x99);ae->nop+=1;ae->tick+=4;break; + case CRC_D:___output(ae,0x9A);ae->nop+=1;ae->tick+=4;break; + case CRC_E:___output(ae,0x9B);ae->nop+=1;ae->tick+=4;break; + case CRC_H:___output(ae,0x9C);ae->nop+=1;ae->tick+=4;break; + case CRC_L:___output(ae,0x9D);ae->nop+=1;ae->tick+=4;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x9C);ae->nop+=2;ae->tick+=8;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x9D);ae->nop+=2;ae->tick+=8;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x9C);ae->nop+=2;ae->tick+=8;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x9D);ae->nop+=2;ae->tick+=8;break; + case CRC_IX:case CRC_IY: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use SBC with A,B,C,D,E,H,L,XH,XL,YH,YL,(HL),(IX),(IY)\n"); + ae->idx++; + return; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0x9E); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0x9E); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else { + ___output(ae,0xDE); + PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); + ae->nop+=2;ae->tick+=7; + } + } + ae->idx++; + } else if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_HL: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_BC:___output(ae,0xED);___output(ae,0x42);ae->nop+=4;ae->tick+=15;break; + case CRC_DE:___output(ae,0xED);___output(ae,0x52);ae->nop+=4;ae->tick+=15;break; + case CRC_HL:___output(ae,0xED);___output(ae,0x62);ae->nop+=4;ae->tick+=15;break; + case CRC_SP:___output(ae,0xED);___output(ae,0x72);ae->nop+=4;ae->tick+=15;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SBC HL,[BC,DE,HL,SP]\n"); + } + break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SBC HL,[BC,DE,HL,SP]\n"); + } + ae->idx+=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid syntax for SBC\n"); + } +} + +void _ADC(struct s_assenv *ae) { + if ((!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) || ((!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) && strcmp(ae->wl[ae->idx+1].w,"A")==0)) { + if (!ae->wl[ae->idx+1].t) ae->idx++; + /* also implicit A */ + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_A:___output(ae,0x8F);ae->nop+=1;ae->tick+=4;break; + case CRC_MHL:___output(ae,0x8E);ae->nop+=2;ae->tick+=7;break; + case CRC_B:___output(ae,0x88);ae->nop+=1;ae->tick+=4;break; + case CRC_C:___output(ae,0x89);ae->nop+=1;ae->tick+=4;break; + case CRC_D:___output(ae,0x8A);ae->nop+=1;ae->tick+=4;break; + case CRC_E:___output(ae,0x8B);ae->nop+=1;ae->tick+=4;break; + case CRC_H:___output(ae,0x8C);ae->nop+=1;ae->tick+=4;break; + case CRC_L:___output(ae,0x8D);ae->nop+=1;ae->tick+=4;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x8C);ae->nop+=2;ae->tick+=8;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x8D);ae->nop+=2;ae->tick+=8;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x8C);ae->nop+=2;ae->tick+=8;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x8D);ae->nop+=2;ae->tick+=8;break; + case CRC_IX:case CRC_IY: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use ADC with A,B,C,D,E,H,L,XH,XL,YH,YL,(HL),(IX),(IY)\n"); + ae->idx++; + return; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0x8E); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0x8E); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else { + ___output(ae,0xCE); + PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); + ae->nop+=2;ae->tick+=7; + } + } + ae->idx++; + } else if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_HL: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_BC:___output(ae,0xED);___output(ae,0x4A);ae->nop+=4;ae->tick+=15;break; + case CRC_DE:___output(ae,0xED);___output(ae,0x5A);ae->nop+=4;ae->tick+=15;break; + case CRC_HL:___output(ae,0xED);___output(ae,0x6A);ae->nop+=4;ae->tick+=15;break; + case CRC_SP:___output(ae,0xED);___output(ae,0x7A);ae->nop+=4;ae->tick+=15;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is ADC HL,[BC,DE,HL,SP]\n"); + } + break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is ADC HL,[BC,DE,HL,SP]\n"); + } + ae->idx+=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid syntax for ADC\n"); + } +} + +void _ADD(struct s_assenv *ae) { + if ((!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) || ((!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) && strcmp(ae->wl[ae->idx+1].w,"A")==0)) { + if (!ae->wl[ae->idx+1].t) ae->idx++; + /* also implicit A */ + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_A:___output(ae,0x87);ae->nop+=1;ae->tick+=4;break; + case CRC_MHL:___output(ae,0x86);ae->nop+=2;ae->tick+=7;break; + case CRC_B:___output(ae,0x80);ae->nop+=1;ae->tick+=4;break; + case CRC_C:___output(ae,0x81);ae->nop+=1;ae->tick+=4;break; + case CRC_D:___output(ae,0x82);ae->nop+=1;ae->tick+=4;break; + case CRC_E:___output(ae,0x83);ae->nop+=1;ae->tick+=4;break; + case CRC_H:___output(ae,0x84);ae->nop+=1;ae->tick+=4;break; + case CRC_L:___output(ae,0x85);ae->nop+=1;ae->tick+=4;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x84);ae->nop+=2;ae->tick+=8;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x85);ae->nop+=2;ae->tick+=8;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x84);ae->nop+=2;ae->tick+=8;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x85);ae->nop+=2;ae->tick+=8;break; + case CRC_IX:case CRC_IY: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use ADD with A,B,C,D,E,H,L,XH,XL,YH,YL,(HL),(IX),(IY)\n"); + ae->idx++; + return; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0x86); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0x86); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else { + ___output(ae,0xC6); + PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); + ae->nop+=2;ae->tick+=7; + } + } + ae->idx++; + } else if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_HL: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_BC:___output(ae,0x09);ae->nop+=3;ae->tick+=11;break; + case CRC_DE:___output(ae,0x19);ae->nop+=3;ae->tick+=11;break; + case CRC_HL:___output(ae,0x29);ae->nop+=3;ae->tick+=11;break; + case CRC_SP:___output(ae,0x39);ae->nop+=3;ae->tick+=11;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is ADD HL,[BC,DE,HL,SP]\n"); + } + break; + case CRC_IX: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_BC:___output(ae,0xDD);___output(ae,0x09);ae->nop+=4;ae->tick+=15;break; + case CRC_DE:___output(ae,0xDD);___output(ae,0x19);ae->nop+=4;ae->tick+=15;break; + case CRC_IX:___output(ae,0xDD);___output(ae,0x29);ae->nop+=4;ae->tick+=15;break; + case CRC_SP:___output(ae,0xDD);___output(ae,0x39);ae->nop+=4;ae->tick+=15;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is ADD IX,[BC,DE,IX,SP]\n"); + } + break; + case CRC_IY: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_BC:___output(ae,0xFD);___output(ae,0x09);ae->nop+=4;ae->tick+=15;break; + case CRC_DE:___output(ae,0xFD);___output(ae,0x19);ae->nop+=4;ae->tick+=15;break; + case CRC_IY:___output(ae,0xFD);___output(ae,0x29);ae->nop+=4;ae->tick+=15;break; + case CRC_SP:___output(ae,0xFD);___output(ae,0x39);ae->nop+=4;ae->tick+=15;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is ADD IY,[BC,DE,IY,SP]\n"); + } + break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is ADD [HL,IX,IY],reg16\n"); + } + ae->idx+=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid syntax for ADD\n"); + } +} + +void _CP(struct s_assenv *ae) { + if ((!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) || ((!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) && strcmp(ae->wl[ae->idx+1].w,"A")==0)) { + if (!ae->wl[ae->idx+1].t) ae->idx++; + /* also implicit A */ + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_A:___output(ae,0xBF);ae->nop+=1;ae->tick+=4;break; + case CRC_MHL:___output(ae,0xBE);ae->nop+=2;ae->tick+=7;break; + case CRC_B:___output(ae,0xB8);ae->nop+=1;ae->tick+=4;break; + case CRC_C:___output(ae,0xB9);ae->nop+=1;ae->tick+=4;break; + case CRC_D:___output(ae,0xBA);ae->nop+=1;ae->tick+=4;break; + case CRC_E:___output(ae,0xBB);ae->nop+=1;ae->tick+=4;break; + case CRC_H:___output(ae,0xBC);ae->nop+=1;ae->tick+=4;break; + case CRC_L:___output(ae,0xBD);ae->nop+=1;ae->tick+=4;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0xBC);ae->nop+=2;ae->tick+=8;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0xBD);ae->nop+=2;ae->tick+=8;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0xBC);ae->nop+=2;ae->tick+=8;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0xBD);ae->nop+=2;ae->tick+=8;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0xBE); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0xBE); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else { + ___output(ae,0xFE); + PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); + ae->nop+=2;ae->tick+=7; + } + } + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Syntax is CP reg8/(reg16)\n"); + } +} + +void _RET(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_NZ:___output(ae,0xC0);ae->nop+=2;ae->tick+=5;break; + case CRC_Z:___output(ae,0xC8);ae->nop+=2;ae->tick+=5;break; + case CRC_C:___output(ae,0xD8);ae->nop+=2;ae->tick+=5;break; + case CRC_NC:___output(ae,0xD0);ae->nop+=2;ae->tick+=5;break; + case CRC_PE:___output(ae,0xE8);ae->nop+=2;ae->tick+=5;break; + case CRC_PO:___output(ae,0xE0);ae->nop+=2;ae->tick+=5;break; + case CRC_P:___output(ae,0xF0);ae->nop+=2;ae->tick+=5;break; + case CRC_M:___output(ae,0xF8);ae->nop+=2;ae->tick+=5;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Available flags for RET are C,NC,Z,NZ,PE,PO,P,M\n"); + } + ae->idx++; + } else if (ae->wl[ae->idx].t==1) { + ___output(ae,0xC9); + ae->nop+=3;ae->tick+=10; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid RET syntax\n"); + } +} + +void _CALL(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==0 && ae->wl[ae->idx+2].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_C:___output(ae,0xDC);ae->nop+=3;ae->tick+=10;break; + case CRC_Z:___output(ae,0xCC);ae->nop+=3;ae->tick+=10;break; + case CRC_NZ:___output(ae,0xC4);ae->nop+=3;ae->tick+=10;break; + case CRC_NC:___output(ae,0xD4);ae->nop+=3;ae->tick+=10;break; + case CRC_PE:___output(ae,0xEC);ae->nop+=3;ae->tick+=10;break; + case CRC_PO:___output(ae,0xE4);ae->nop+=3;ae->tick+=10;break; + case CRC_P:___output(ae,0xF4);ae->nop+=3;ae->tick+=10;break; + case CRC_M:___output(ae,0xFC);ae->nop+=3;ae->tick+=10;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Available flags for CALL are C,NC,Z,NZ,PE,PO,P,M\n"); + } + PushExpression(ae,ae->idx+2,E_EXPRESSION_J16C); + ae->idx+=2; + } else if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ___output(ae,0xCD); + PushExpression(ae,ae->idx+1,E_EXPRESSION_J16C); + ae->idx++; + ae->nop+=5;ae->tick+=17; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid CALL syntax\n"); + } +} + +void _JR(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==0 && ae->wl[ae->idx+2].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_NZ:___output(ae,0x20);ae->nop+=2;ae->tick+=7;break; + case CRC_C:___output(ae,0x38);ae->nop+=2;ae->tick+=7;break; + case CRC_Z:___output(ae,0x28);ae->nop+=2;ae->tick+=7;break; + case CRC_NC:___output(ae,0x30);ae->nop+=2;ae->tick+=7;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Available flags for JR are C,NC,Z,NZ\n"); + } + PushExpression(ae,ae->idx+2,E_EXPRESSION_J8); + ae->idx+=2; + } else if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ___output(ae,0x18); + PushExpression(ae,ae->idx+1,E_EXPRESSION_J8); + ae->idx++; + ae->nop+=3;ae->tick+=12; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid JR syntax\n"); + } +} + +void _JP(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==0 && ae->wl[ae->idx+2].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_C:___output(ae,0xDA);ae->nop+=3;ae->tick+=10;break; + case CRC_Z:___output(ae,0xCA);ae->nop+=3;ae->tick+=10;break; + case CRC_NZ:___output(ae,0xC2);ae->nop+=3;ae->tick+=10;break; + case CRC_NC:___output(ae,0xD2);ae->nop+=3;ae->tick+=10;break; + case CRC_PE:___output(ae,0xEA);ae->nop+=3;ae->tick+=10;break; + case CRC_PO:___output(ae,0xE2);ae->nop+=3;ae->tick+=10;break; + case CRC_P:___output(ae,0xF2);ae->nop+=3;ae->tick+=10;break; + case CRC_M:___output(ae,0xFA);ae->nop+=3;ae->tick+=10;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Available flags for JP are C,NC,Z,NZ,PE,PO,P,M\n"); + } + if (!strcmp(ae->wl[ae->idx+2].w,"(IX)") || !strcmp(ae->wl[ae->idx+2].w,"(IY)")) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"conditionnal JP cannot use register addressing\n"); + } else { + PushExpression(ae,ae->idx+2,E_EXPRESSION_J16); + } + ae->idx+=2; + } else if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_HL:case CRC_MHL:___output(ae,0xE9);ae->nop+=1;ae->tick+=4;break; + case CRC_IX:case CRC_MIX:___output(ae,0xDD);___output(ae,0xE9);ae->nop+=2;ae->tick+=8;break; + case CRC_IY:case CRC_MIY:___output(ae,0xFD);___output(ae,0xE9);ae->nop+=2;ae->tick+=8;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0 || strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"JP (IX) or JP (IY) only\n"); + } else { + ___output(ae,0xC3); + PushExpression(ae,ae->idx+1,E_EXPRESSION_J16); + ae->tick+=10; + ae->nop+=3; + } + } + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid JP syntax\n"); + } +} + + +void _DEC(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + do { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_A:___output(ae,0x3D);ae->nop+=1;ae->tick+=4;break; + case CRC_B:___output(ae,0x05);ae->nop+=1;ae->tick+=4;break; + case CRC_C:___output(ae,0x0D);ae->nop+=1;ae->tick+=4;break; + case CRC_D:___output(ae,0x15);ae->nop+=1;ae->tick+=4;break; + case CRC_E:___output(ae,0x1D);ae->nop+=1;ae->tick+=4;break; + case CRC_H:___output(ae,0x25);ae->nop+=1;ae->tick+=4;break; + case CRC_L:___output(ae,0x2D);ae->nop+=1;ae->tick+=4;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x25);ae->nop+=2;ae->tick+=8;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x2D);ae->nop+=2;ae->tick+=8;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x25);ae->nop+=2;ae->tick+=8;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x2D);ae->nop+=2;ae->tick+=8;break; + case CRC_BC:___output(ae,0x0B);ae->nop+=2;ae->tick+=6;break; + case CRC_DE:___output(ae,0x1B);ae->nop+=2;ae->tick+=6;break; + case CRC_HL:___output(ae,0x2B);ae->nop+=2;ae->tick+=6;break; + case CRC_IX:___output(ae,0xDD);___output(ae,0x2B);ae->nop+=3;ae->tick+=10;break; + case CRC_IY:___output(ae,0xFD);___output(ae,0x2B);ae->nop+=3;ae->tick+=10;break; + case CRC_SP:___output(ae,0x3B);ae->nop+=2;ae->tick+=6;break; + case CRC_MHL:___output(ae,0x35);ae->nop+=3;ae->tick+=11;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0x35); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=6;ae->tick+=23; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0x35); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=6;ae->tick+=23; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use DEC with A,B,C,D,E,H,L,XH,XL,YH,YL,BC,DE,HL,SP,(HL),(IX),(IY)\n"); + } + } + ae->idx++; + } while (ae->wl[ae->idx].t==0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use DEC with A,B,C,D,E,H,L,XH,XL,YH,YL,BC,DE,HL,SP,(HL),(IX),(IY)\n"); + } +} +void _INC(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + do { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_A:___output(ae,0x3C);ae->nop+=1;ae->tick+=4;break; + case CRC_B:___output(ae,0x04);ae->nop+=1;ae->tick+=4;break; + case CRC_C:___output(ae,0x0C);ae->nop+=1;ae->tick+=4;break; + case CRC_D:___output(ae,0x14);ae->nop+=1;ae->tick+=4;break; + case CRC_E:___output(ae,0x1C);ae->nop+=1;ae->tick+=4;break; + case CRC_H:___output(ae,0x24);ae->nop+=1;ae->tick+=4;break; + case CRC_L:___output(ae,0x2C);ae->nop+=1;ae->tick+=4;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x24);ae->nop+=2;ae->tick+=8;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x2C);ae->nop+=2;ae->tick+=8;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x24);ae->nop+=2;ae->tick+=8;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x2C);ae->nop+=2;ae->tick+=8;break; + case CRC_BC:___output(ae,0x03);ae->nop+=2;ae->tick+=6;break; + case CRC_DE:___output(ae,0x13);ae->nop+=2;ae->tick+=6;break; + case CRC_HL:___output(ae,0x23);ae->nop+=2;ae->tick+=6;break; + case CRC_IX:___output(ae,0xDD);___output(ae,0x23);ae->nop+=3;ae->tick+=10;break; + case CRC_IY:___output(ae,0xFD);___output(ae,0x23);ae->nop+=3;ae->tick+=10;break; + case CRC_SP:___output(ae,0x33);ae->nop+=2;ae->tick+=6;break; + case CRC_MHL:___output(ae,0x34);ae->nop+=3;ae->tick+=11;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0x34); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=6;ae->tick+=23; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0x34); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=6;ae->tick+=23; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use INC with A,B,C,D,E,H,L,XH,XL,YH,YL,BC,DE,HL,SP,(HL),(IX),(IY)\n"); + } + } + ae->idx++; + } while (ae->wl[ae->idx].t==0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use INC with A,B,C,D,E,H,L,XH,XL,YH,YL,BC,DE,HL,SP,(HL),(IX),(IY)\n"); + } +} + +void _SUB(struct s_assenv *ae) { + #ifdef OPCODE + #undef OPCODE + #endif + #define OPCODE 0x90 + + if ((!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) || ((!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) && strcmp(ae->wl[ae->idx+1].w,"A")==0)) { + if (!ae->wl[ae->idx+1].t) ae->idx++; + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_A:___output(ae,OPCODE+7);ae->nop+=1;ae->tick+=4;break; + case CRC_MHL:___output(ae,OPCODE+6);ae->nop+=2;ae->tick+=7;break; + case CRC_B:___output(ae,OPCODE);ae->nop+=1;ae->tick+=4;break; + case CRC_C:___output(ae,OPCODE+1);ae->nop+=1;ae->tick+=4;break; + case CRC_D:___output(ae,OPCODE+2);ae->nop+=1;ae->tick+=4;break; + case CRC_E:___output(ae,OPCODE+3);ae->nop+=1;ae->tick+=4;break; + case CRC_H:___output(ae,OPCODE+4);ae->nop+=1;ae->tick+=4;break; + case CRC_L:___output(ae,OPCODE+5);ae->nop+=1;ae->tick+=4;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,OPCODE+4);ae->nop+=2;ae->tick+=8;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,OPCODE+5);ae->nop+=2;ae->tick+=8;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,OPCODE+4);ae->nop+=2;ae->tick+=8;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,OPCODE+5);ae->nop+=2;ae->tick+=8;break; + case CRC_IX:case CRC_IY: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use SUB with A,B,C,D,E,H,L,XH,XL,YH,YL,(HL),(IX),(IY)\n"); + ae->idx++; + return; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,OPCODE+6); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,OPCODE+6); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else { + ___output(ae,0xD6); + PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); + ae->nop+=2;ae->tick+=7; + } + } + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use SUB with A,B,C,D,E,H,L,XH,XL,YH,YL,(HL),(IX),(IY)\n"); + } +} +void _AND(struct s_assenv *ae) { + #ifdef OPCODE + #undef OPCODE + #endif + #define OPCODE 0xA0 + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_A:___output(ae,OPCODE+7);ae->nop+=1;ae->tick+=4;break; + case CRC_MHL:___output(ae,OPCODE+6);ae->nop+=2;ae->tick+=7;break; + case CRC_B:___output(ae,OPCODE);ae->nop+=1;ae->tick+=4;break; + case CRC_C:___output(ae,OPCODE+1);ae->nop+=1;ae->tick+=4;break; + case CRC_D:___output(ae,OPCODE+2);ae->nop+=1;ae->tick+=4;break; + case CRC_E:___output(ae,OPCODE+3);ae->nop+=1;ae->tick+=4;break; + case CRC_H:___output(ae,OPCODE+4);ae->nop+=1;ae->tick+=4;break; + case CRC_L:___output(ae,OPCODE+5);ae->nop+=1;ae->tick+=4;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,OPCODE+4);ae->nop+=2;ae->tick+=8;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,OPCODE+5);ae->nop+=2;ae->tick+=8;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,OPCODE+4);ae->nop+=2;ae->tick+=8;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,OPCODE+5);ae->nop+=2;ae->tick+=8;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,OPCODE+6); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,OPCODE+6); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else { + ___output(ae,0xE6); + PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); + ae->nop+=2;ae->tick+=7; + } + } + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use AND with A,B,C,D,E,H,L,XH,XL,YH,YL,(HL),(IX),(IY)\n"); + } +} +void _OR(struct s_assenv *ae) { + #ifdef OPCODE + #undef OPCODE + #endif + #define OPCODE 0xB0 + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_A:___output(ae,OPCODE+7);ae->nop+=1;ae->tick+=4;break; + case CRC_MHL:___output(ae,OPCODE+6);ae->nop+=2;ae->tick+=7;break; + case CRC_B:___output(ae,OPCODE);ae->nop+=1;ae->tick+=4;break; + case CRC_C:___output(ae,OPCODE+1);ae->nop+=1;ae->tick+=4;break; + case CRC_D:___output(ae,OPCODE+2);ae->nop+=1;ae->tick+=4;break; + case CRC_E:___output(ae,OPCODE+3);ae->nop+=1;ae->tick+=4;break; + case CRC_H:___output(ae,OPCODE+4);ae->nop+=1;ae->tick+=4;break; + case CRC_L:___output(ae,OPCODE+5);ae->nop+=1;ae->tick+=4;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,OPCODE+4);ae->nop+=2;ae->tick+=8;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,OPCODE+5);ae->nop+=2;ae->tick+=8;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,OPCODE+4);ae->nop+=2;ae->tick+=8;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,OPCODE+5);ae->nop+=2;ae->tick+=8;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,OPCODE+6); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,OPCODE+6); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else { + ___output(ae,0xF6); + PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); + ae->nop+=2;ae->tick+=7; + } + } + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use OR with A,B,C,D,E,H,L,XH,XL,YH,YL,(HL),(IX),(IY)\n"); + } +} +void _XOR(struct s_assenv *ae) { + #ifdef OPCODE + #undef OPCODE + #endif + #define OPCODE 0xA8 + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_A:___output(ae,OPCODE+7);ae->nop+=1;ae->tick+=4;break; + case CRC_MHL:___output(ae,OPCODE+6);ae->nop+=2;ae->tick+=7;break; + case CRC_B:___output(ae,OPCODE);ae->nop+=1;ae->tick+=4;break; + case CRC_C:___output(ae,OPCODE+1);ae->nop+=1;ae->tick+=4;break; + case CRC_D:___output(ae,OPCODE+2);ae->nop+=1;ae->tick+=4;break; + case CRC_E:___output(ae,OPCODE+3);ae->nop+=1;ae->tick+=4;break; + case CRC_H:___output(ae,OPCODE+4);ae->nop+=1;ae->tick+=4;break; + case CRC_L:___output(ae,OPCODE+5);ae->nop+=1;ae->tick+=4;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,OPCODE+4);ae->nop+=2;ae->tick+=8;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,OPCODE+5);ae->nop+=2;ae->tick+=8;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,OPCODE+4);ae->nop+=2;ae->tick+=8;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,OPCODE+5);ae->nop+=2;ae->tick+=8;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,OPCODE+6); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,OPCODE+6); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else { + ___output(ae,0xEE); + PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); + ae->nop+=2;ae->tick+=7; + } + } + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use XOR with A,B,C,D,E,H,L,XH,XL,YH,YL,(HL),(IX),(IY)\n"); + } +} + + +void _POP(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + switch (GetCRC(ae->wl[ae->idx].w)) { + case CRC_AF:___output(ae,0xF1);ae->nop+=3;ae->tick+=10;break; + case CRC_BC:___output(ae,0xC1);ae->nop+=3;ae->tick+=10;break; + case CRC_DE:___output(ae,0xD1);ae->nop+=3;ae->tick+=10;break; + case CRC_HL:___output(ae,0xE1);ae->nop+=3;ae->tick+=10;break; + case CRC_IX:___output(ae,0xDD);___output(ae,0xE1);ae->nop+=4;ae->tick+=14;break; + case CRC_IY:___output(ae,0xFD);___output(ae,0xE1);ae->nop+=4;ae->tick+=14;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use POP with AF,BC,DE,HL,IX,IY\n"); + } + } while (ae->wl[ae->idx].t!=1); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"POP need at least one parameter\n"); + } +} +void _PUSH(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + switch (GetCRC(ae->wl[ae->idx].w)) { + case CRC_AF:___output(ae,0xF5);ae->nop+=4;ae->tick+=11;break; + case CRC_BC:___output(ae,0xC5);ae->nop+=4;ae->tick+=11;break; + case CRC_DE:___output(ae,0xD5);ae->nop+=4;ae->tick+=11;break; + case CRC_HL:___output(ae,0xE5);ae->nop+=4;ae->tick+=11;break; + case CRC_IX:___output(ae,0xDD);___output(ae,0xE5);ae->nop+=5;ae->tick+=15;break; + case CRC_IY:___output(ae,0xFD);___output(ae,0xE5);ae->nop+=5;ae->tick+=15;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use PUSH with AF,BC,DE,HL,IX,IY\n"); + } + } while (ae->wl[ae->idx].t!=1); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"PUSH need at least one parameter\n"); + } +} + +void _IM(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + /* la valeur du parametre va definir l'opcode du IM */ + ___output(ae,0xED); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IM); + ae->idx++; + ae->nop+=2; + ae->tick+=8; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IM need one parameter\n"); + } +} + +void _RLCA(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0x7); + ae->nop+=1; + ae->tick+=4; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RLCA does not need parameter\n"); + } +} +void _RRCA(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xF); + ae->nop+=1; + ae->tick+=4; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RRCA does not need parameter\n"); + } +} +void _NEG(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0x44); + ae->nop+=2; + ae->tick+=8; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"NEG does not need parameter\n"); + } +} +void _DAA(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0x27); + ae->nop+=1; + ae->tick+=4; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DAA does not need parameter\n"); + } +} +void _CPL(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0x2F); + ae->nop+=1; + ae->tick+=4; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CPL does not need parameter\n"); + } +} +void _RETI(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0x4D); + ae->nop+=4; + ae->tick+=14; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RETI does not need parameter\n"); + } +} +void _SCF(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0x37); + ae->nop+=1; + ae->tick+=4; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SCF does not need parameter\n"); + } +} +void _LDD(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xA8); + ae->nop+=5; + ae->tick+=16; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LDD does not need parameter\n"); + } +} +void _LDDR(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xB8); + ae->nop+=5; + ae->tick+=16; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LDDR does not need parameter\n"); + } +} +void _LDI(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xA0); + ae->nop+=5; + ae->tick+=16; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LDI does not need parameter\n"); + } +} +void _LDIR(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xB0); + ae->nop+=5; + ae->tick+=16; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LDIR does not need parameter\n"); + } +} +void _CCF(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0x3F); + ae->nop+=1; + ae->tick+=4; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CCF does not need parameter\n"); + } +} +void _CPD(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xA9); + ae->nop+=4; + ae->tick+=16; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CPD does not need parameter\n"); + } +} +void _CPDR(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xB9); + ae->nop+=4; + ae->tick+=16; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CPDR does not need parameter\n"); + } +} +void _CPI(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xA1); + ae->nop+=4; + ae->tick+=16; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CPI does not need parameter\n"); + } +} +void _CPIR(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xB1); + ae->nop+=4; + ae->tick+=16; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CPIR does not need parameter\n"); + } +} +void _OUTD(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xAB); + ae->nop+=5; + ae->tick+=16; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"OUTD does not need parameter\n"); + } +} +void _OTDR(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xBB); + ae->nop+=5; + ae->tick+=16; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"OTDR does not need parameter\n"); + } +} +void _OUTI(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xA3); + ae->nop+=5; + ae->tick+=16; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"OUTI does not need parameter\n"); + } +} +void _OTIR(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xB3); + ae->nop+=5; + ae->tick+=16; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"OTIR does not need parameter\n"); + } +} +void _RETN(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0x45); + ae->nop+=4; + ae->tick+=14; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RETN does not need parameter\n"); + } +} +void _IND(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xAA); + ae->nop+=5; + ae->tick+=16; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IND does not need parameter\n"); + } +} +void _INDR(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xBA); + ae->nop+=5; + ae->tick+=16; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INDR does not need parameter\n"); + } +} +void _INI(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xA2); + ae->nop+=5; + ae->tick+=16; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INI does not need parameter\n"); + } +} +void _INIR(struct s_assenv *ae) { + if (ae->wl[ae->idx].t==1) { + ___output(ae,0xED); + ___output(ae,0xB2); + ae->nop+=5; + ae->tick+=16; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INIR does not need parameter\n"); + } +} +void _EXX(struct s_assenv *ae) { + if (ae->wl[ae->idx].t==1) { + ___output(ae,0xD9); + ae->nop+=1; + ae->tick+=4; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"EXX does not need parameter\n"); + } +} +void _HALT(struct s_assenv *ae) { + if (ae->wl[ae->idx].t==1) { + ___output(ae,0x76); + ae->nop+=1; + ae->tick+=4; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"HALT does not need parameter\n"); + } +} + +void _RLA(struct s_assenv *ae) { + if (ae->wl[ae->idx].t==1) { + ___output(ae,0x17); + ae->nop+=1; + ae->tick+=4; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RLA does not need parameter\n"); + } +} +void _RRA(struct s_assenv *ae) { + if (ae->wl[ae->idx].t==1) { + ___output(ae,0x1F); + ae->nop+=1; + ae->tick+=4; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RRA does not need parameter\n"); + } +} +void _RLD(struct s_assenv *ae) { + if (ae->wl[ae->idx].t==1) { + ___output(ae,0xED); + ___output(ae,0x6F); + ae->nop+=5; + ae->tick+=18; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RLD does not need parameter\n"); + } +} +void _RRD(struct s_assenv *ae) { + if (ae->wl[ae->idx].t==1) { + ___output(ae,0xED); + ___output(ae,0x67); + ae->nop+=5; + ae->tick+=18; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RRD does not need parameter\n"); + } +} + + +void _EXA(struct s_assenv *ae) { + if (ae->wl[ae->idx].t==1) { + ___output(ae,0x08);ae->nop+=1; + ae->tick+=4; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"EXA alias does not need parameter\n"); + } +} + +void _NOP(struct s_assenv *ae) { + int o; + + if (ae->wl[ae->idx].t) { + ___output(ae,0x00); + ae->nop+=1; + ae->tick+=4; + } else if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + o=RoundComputeExpressionCore(ae,ae->wl[ae->idx+1].w,ae->codeadr,0); + if (o>=0) { + while (o>0) { + ___output(ae,0x00); + ae->nop+=1; + ae->tick+=4; + o--; + } + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"NOP is supposed to be used without parameter or with one optional parameter\n"); + } +} +void _DI(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xF3); + ae->nop+=1; + ae->tick+=4; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DI does not need parameter\n"); + } +} +void _EI(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xFB); + ae->nop+=1; + ae->tick+=4; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"EI does not need parameter\n"); + } +} + +void _RST(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t!=2) { + if (!strcmp(ae->wl[ae->idx+1].w,"(IY)") || !strcmp(ae->wl[ae->idx+1].w,"(IX)")) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RST cannot use IX or IY\n"); + } else { + /* la valeur du parametre va definir l'opcode du RST */ + PushExpression(ae,ae->idx+1,E_EXPRESSION_RST); + } + ae->idx++; + ae->nop+=4; + ae->tick+=11; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RST need one parameter\n"); + } +} + +void _DJNZ(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + if (IsRegister(ae->wl[ae->idx+1].w)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DJNZ cannot use register\n"); + } else if (strcmp("(IX)",ae->wl[ae->idx+1].w)==0 || strcmp("(IY)",ae->wl[ae->idx+1].w)==0) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DJNZ cannot use register\n"); + } else { + ___output(ae,0x10); + PushExpression(ae,ae->idx+1,E_EXPRESSION_J8); + ae->nop+=3; + ae->tick+=13; + } + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DJNZ need one parameter\n"); + } +} + +void _LD(struct s_assenv *ae) { + /* on check qu'il y a au moins deux parametres */ + if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_A: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_I:___output(ae,0xED);___output(ae,0x57);ae->nop+=3;ae->tick+=9;break; + case CRC_R:___output(ae,0xED);___output(ae,0x5F);ae->nop+=3;ae->tick+=9;break; + case CRC_B:___output(ae,0x78);ae->nop+=1;ae->tick+=4;break; + case CRC_C:___output(ae,0x79);ae->nop+=1;ae->tick+=4;break; + case CRC_D:___output(ae,0x7A);ae->nop+=1;ae->tick+=4;break; + case CRC_E:___output(ae,0x7B);ae->nop+=1;ae->tick+=4;break; + case CRC_H:___output(ae,0x7C);ae->nop+=1;ae->tick+=4;break; + case CRC_L:___output(ae,0x7D);ae->nop+=1;ae->tick+=4;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x7C);ae->nop+=2;ae->tick+=8;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x7D);ae->nop+=2;ae->tick+=8;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x7C);ae->nop+=2;ae->tick+=8;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x7D);ae->nop+=2;ae->tick+=8;break; + case CRC_MHL:___output(ae,0x7E);ae->nop+=2;ae->tick+=7;break; + case CRC_A:___output(ae,0x7F);ae->nop+=1;ae->tick+=4;break; + case CRC_MBC:___output(ae,0x0A);ae->nop+=2;ae->tick+=7;break; + case CRC_MDE:___output(ae,0x1A);ae->nop+=2;ae->tick+=7;break; + default: + /* (ix+expression) (iy+expression) (expression) expression */ + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0x7E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0x7E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else if (StringIsMem(ae->wl[ae->idx+2].w)) { + ___output(ae,0x3A); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V16); + ae->nop+=4;ae->tick+=13; + } else { + ___output(ae,0x3E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=2;ae->tick+=7; + } + } + break; + case CRC_I: + if (GetCRC(ae->wl[ae->idx+2].w)==CRC_A) { + ___output(ae,0xED);___output(ae,0x47); + ae->nop+=3;ae->tick+=9; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD I,A only\n"); + } + break; + case CRC_R: + if (GetCRC(ae->wl[ae->idx+2].w)==CRC_A) { + ___output(ae,0xED);___output(ae,0x4F); + ae->nop+=3;ae->tick+=9; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD R,A only\n"); + } + break; + case CRC_B: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0x40);ae->nop+=1;ae->tick+=4;break; + case CRC_C:___output(ae,0x41);ae->nop+=1;ae->tick+=4;break; + case CRC_D:___output(ae,0x42);ae->nop+=1;ae->tick+=4;break; + case CRC_E:___output(ae,0x43);ae->nop+=1;ae->tick+=4;break; + case CRC_H:___output(ae,0x44);ae->nop+=1;ae->tick+=4;break; + case CRC_L:___output(ae,0x45);ae->nop+=1;ae->tick+=4;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x44);ae->nop+=2;ae->tick+=8;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x45);ae->nop+=2;ae->tick+=8;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x44);ae->nop+=2;ae->tick+=8;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x45);ae->nop+=2;ae->tick+=8;break; + case CRC_MHL:___output(ae,0x46);ae->nop+=2;ae->tick+=7;break; + case CRC_A:___output(ae,0x47);ae->nop+=1;ae->tick+=4;break; + default: + /* (ix+expression) (iy+expression) expression */ + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0x46); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0x46); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else { + ___output(ae,0x06); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=2;ae->tick+=7; + } + } + break; + case CRC_C: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0x48);ae->nop+=1;ae->tick+=4;break; + case CRC_C:___output(ae,0x49);ae->nop+=1;ae->tick+=4;break; + case CRC_D:___output(ae,0x4A);ae->nop+=1;ae->tick+=4;break; + case CRC_E:___output(ae,0x4B);ae->nop+=1;ae->tick+=4;break; + case CRC_H:___output(ae,0x4C);ae->nop+=1;ae->tick+=4;break; + case CRC_L:___output(ae,0x4D);ae->nop+=1;ae->tick+=4;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x4C);ae->nop+=2;ae->tick+=8;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x4D);ae->nop+=2;ae->tick+=8;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x4C);ae->nop+=2;ae->tick+=8;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x4D);ae->nop+=2;ae->tick+=8;break; + case CRC_MHL:___output(ae,0x4E);ae->nop+=2;ae->tick+=7;break; + case CRC_A:___output(ae,0x4F);ae->nop+=1;ae->tick+=4;break; + default: + /* (ix+expression) (iy+expression) expression */ + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0x4E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0x4E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else { + ___output(ae,0x0E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=2;ae->tick+=7; + } + } + break; + case CRC_D: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0x50);ae->nop+=1;ae->tick+=4;break; + case CRC_C:___output(ae,0x51);ae->nop+=1;ae->tick+=4;break; + case CRC_D:___output(ae,0x52);ae->nop+=1;ae->tick+=4;break; + case CRC_E:___output(ae,0x53);ae->nop+=1;ae->tick+=4;break; + case CRC_H:___output(ae,0x54);ae->nop+=1;ae->tick+=4;break; + case CRC_L:___output(ae,0x55);ae->nop+=1;ae->tick+=4;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x54);ae->nop+=2;ae->tick+=8;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x55);ae->nop+=2;ae->tick+=8;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x54);ae->nop+=2;ae->tick+=8;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x55);ae->nop+=2;ae->tick+=8;break; + case CRC_MHL:___output(ae,0x56);ae->nop+=2;ae->tick+=7;break; + case CRC_A:___output(ae,0x57);ae->nop+=1;ae->tick+=4;break; + default: + /* (ix+expression) (iy+expression) expression */ + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0x56); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0x56); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else { + ___output(ae,0x16); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=2;ae->tick+=7; + } + } + break; + case CRC_E: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0x58);ae->nop+=1;ae->tick+=4;break; + case CRC_C:___output(ae,0x59);ae->nop+=1;ae->tick+=4;break; + case CRC_D:___output(ae,0x5A);ae->nop+=1;ae->tick+=4;break; + case CRC_E:___output(ae,0x5B);ae->nop+=1;ae->tick+=4;break; + case CRC_H:___output(ae,0x5C);ae->nop+=1;ae->tick+=4;break; + case CRC_L:___output(ae,0x5D);ae->nop+=1;ae->tick+=4;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x5C);ae->nop+=2;ae->tick+=8;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x5D);ae->nop+=2;ae->tick+=8;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x5C);ae->nop+=2;ae->tick+=8;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x5D);ae->nop+=2;ae->tick+=8;break; + case CRC_MHL:___output(ae,0x5E);ae->nop+=2;ae->tick+=7;break; + case CRC_A:___output(ae,0x5F);ae->nop+=1;ae->tick+=4;break; + default: + /* (ix+expression) (iy+expression) expression */ + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0x5E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0x5E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else { + ___output(ae,0x1E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=2;ae->tick+=7; + } + } + break; + case CRC_IYH:case CRC_HY:case CRC_YH: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0xFD);___output(ae,0x60);ae->nop+=2;ae->tick+=8;break; + case CRC_C:___output(ae,0xFD);___output(ae,0x61);ae->nop+=2;ae->tick+=8;break; + case CRC_D:___output(ae,0xFD);___output(ae,0x62);ae->nop+=2;ae->tick+=8;break; + case CRC_E:___output(ae,0xFD);___output(ae,0x63);ae->nop+=2;ae->tick+=8;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x64);ae->nop+=2;ae->tick+=8;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x65);ae->nop+=2;ae->tick+=8;break; + case CRC_A:___output(ae,0xFD);___output(ae,0x67);ae->nop+=2;ae->tick+=8;break; + default: + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3) && strncmp(ae->wl[ae->idx+2].w,"(IY",3)) { + ___output(ae,0xFD);___output(ae,0x26); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=3;ae->tick+=11; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD iyh,n/r only\n"); + } + } + break; + case CRC_IYL:case CRC_LY:case CRC_YL: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0xFD);___output(ae,0x68);ae->nop+=2;ae->tick+=8;break; + case CRC_C:___output(ae,0xFD);___output(ae,0x69);ae->nop+=2;ae->tick+=8;break; + case CRC_D:___output(ae,0xFD);___output(ae,0x6A);ae->nop+=2;ae->tick+=8;break; + case CRC_E:___output(ae,0xFD);___output(ae,0x6B);ae->nop+=2;ae->tick+=8;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x6C);ae->nop+=2;ae->tick+=8;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x6D);ae->nop+=2;ae->tick+=8;break; + case CRC_A:___output(ae,0xFD);___output(ae,0x6F);ae->nop+=2;ae->tick+=8;break; + default: + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3) && strncmp(ae->wl[ae->idx+2].w,"(IY",3)) { + ___output(ae,0xFD);___output(ae,0x2E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=3;ae->tick+=11; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD iyl,n/r only\n"); + } + } + break; + case CRC_IXH:case CRC_HX:case CRC_XH: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0xDD);___output(ae,0x60);ae->nop+=2;ae->tick+=8;break; + case CRC_C:___output(ae,0xDD);___output(ae,0x61);ae->nop+=2;ae->tick+=8;break; + case CRC_D:___output(ae,0xDD);___output(ae,0x62);ae->nop+=2;ae->tick+=8;break; + case CRC_E:___output(ae,0xDD);___output(ae,0x63);ae->nop+=2;ae->tick+=8;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x64);ae->nop+=2;ae->tick+=8;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x65);ae->nop+=2;ae->tick+=8;break; + case CRC_A:___output(ae,0xDD);___output(ae,0x67);ae->nop+=2;ae->tick+=8;break; + default: + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3) && strncmp(ae->wl[ae->idx+2].w,"(IY",3)) { + ___output(ae,0xDD);___output(ae,0x26); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=3;ae->tick+=11; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD ixh,n/r only\n"); + } + } + break; + case CRC_IXL:case CRC_LX:case CRC_XL: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0xDD);___output(ae,0x68);ae->nop+=2;ae->tick+=8;break; + case CRC_C:___output(ae,0xDD);___output(ae,0x69);ae->nop+=2;ae->tick+=8;break; + case CRC_D:___output(ae,0xDD);___output(ae,0x6A);ae->nop+=2;ae->tick+=8;break; + case CRC_E:___output(ae,0xDD);___output(ae,0x6B);ae->nop+=2;ae->tick+=8;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x6C);ae->nop+=2;ae->tick+=8;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x6D);ae->nop+=2;ae->tick+=8;break; + case CRC_A:___output(ae,0xDD);___output(ae,0x6F);ae->nop+=2;ae->tick+=8;break; + default: + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3) && strncmp(ae->wl[ae->idx+2].w,"(IY",3)) { + ___output(ae,0xDD);___output(ae,0x2E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=3;ae->tick+=11; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD ixl,n/r only\n"); + } + } + break; + case CRC_H: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0x60);ae->nop+=1;ae->tick+=4;break; + case CRC_C:___output(ae,0x61);ae->nop+=1;ae->tick+=4;break; + case CRC_D:___output(ae,0x62);ae->nop+=1;ae->tick+=4;break; + case CRC_E:___output(ae,0x63);ae->nop+=1;ae->tick+=4;break; + case CRC_H:___output(ae,0x64);ae->nop+=1;ae->tick+=4;break; + case CRC_L:___output(ae,0x65);ae->nop+=1;ae->tick+=4;break; + case CRC_MHL:___output(ae,0x66);ae->nop+=2;ae->tick+=7;break; + case CRC_A:___output(ae,0x67);ae->nop+=1;ae->tick+=4;break; + default: + /* (ix+expression) (iy+expression) expression */ + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0x66); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0x66); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else { + ___output(ae,0x26); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=2;ae->tick+=7; + } + } + break; + case CRC_L: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0x68);ae->nop+=1;ae->tick+=4;break; + case CRC_C:___output(ae,0x69);ae->nop+=1;ae->tick+=4;break; + case CRC_D:___output(ae,0x6A);ae->nop+=1;ae->tick+=4;break; + case CRC_E:___output(ae,0x6B);ae->nop+=1;ae->tick+=4;break; + case CRC_H:___output(ae,0x6C);ae->nop+=1;ae->tick+=4;break; + case CRC_L:___output(ae,0x6D);ae->nop+=1;ae->tick+=4;break; + case CRC_MHL:___output(ae,0x6E);ae->nop+=2;ae->tick+=7;break; + case CRC_A:___output(ae,0x6F);ae->nop+=1;ae->tick+=4;break; + default: + /* (ix+expression) (iy+expression) expression */ + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0x6E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0x6E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5;ae->tick+=19; + } else { + ___output(ae,0x2E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=2;ae->tick+=7; + } + } + break; + case CRC_MHL: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0x70);ae->nop+=2;ae->tick+=7;break; + case CRC_C:___output(ae,0x71);ae->nop+=2;ae->tick+=7;break; + case CRC_D:___output(ae,0x72);ae->nop+=2;ae->tick+=7;break; + case CRC_E:___output(ae,0x73);ae->nop+=2;ae->tick+=7;break; + case CRC_H:___output(ae,0x74);ae->nop+=2;ae->tick+=7;break; + case CRC_L:___output(ae,0x75);ae->nop+=2;ae->tick+=7;break; + case CRC_A:___output(ae,0x77);ae->nop+=2;ae->tick+=7;break; + default: + /* expression */ + if (!StringIsMem(ae->wl[ae->idx+2].w)) { + ___output(ae,0x36); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=3;ae->tick+=10; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD (HL),n/r only\n"); + } + } + break; + case CRC_MBC: + if (GetCRC(ae->wl[ae->idx+2].w)==CRC_A) { + ___output(ae,0x02); + ae->nop+=2;ae->tick+=7; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD (BC),A only\n"); + } + break; + case CRC_MDE: + if (GetCRC(ae->wl[ae->idx+2].w)==CRC_A) { + ___output(ae,0x12); + ae->nop+=2;ae->tick+=7; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD (DE),A only\n"); + } + break; + case CRC_HL: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_BC:___output(ae,0x60);___output(ae,0x69);ae->nop+=2;ae->tick+=8;break; + case CRC_DE:___output(ae,0x62);___output(ae,0x6B);ae->nop+=2;ae->tick+=8;break; + case CRC_HL:___output(ae,0x64);___output(ae,0x6D);ae->nop+=2;ae->tick+=8;break; + default: + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0 && (ae->wl[ae->idx+2].w[3]=='+' || ae->wl[ae->idx+2].w[3]=='-')) { + /* enhanced LD HL,(IX+nn) */ + ___output(ae,0xDD);___output(ae,0x66); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV81); + ___output(ae,0xDD);___output(ae,0x6E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=10;ae->tick+=19;ae->tick+=19; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0 && (ae->wl[ae->idx+2].w[3]=='+' || ae->wl[ae->idx+2].w[3]=='-')) { + /* enhanced LD HL,(IY+nn) */ + ___output(ae,0xFD);___output(ae,0x66); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV81); + ___output(ae,0xFD);___output(ae,0x6E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=10;ae->tick+=19;ae->tick+=19; + } else if (StringIsMem(ae->wl[ae->idx+2].w)) { + ___output(ae,0x2A); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V16); + ae->nop+=5;ae->tick+=16; + } else { + ___output(ae,0x21); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V16); + ae->nop+=3;ae->tick+=10; + } + } + break; + case CRC_BC: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_BC:___output(ae,0x40);___output(ae,0x49);ae->nop+=2;ae->tick+=8;break; + case CRC_DE:___output(ae,0x42);___output(ae,0x4B);ae->nop+=2;ae->tick+=8;break; + case CRC_HL:___output(ae,0x44);___output(ae,0x4D);ae->nop+=2;ae->tick+=8;break; + /* enhanced LD BC,IX / LD BC,IY */ + case CRC_IX:___output(ae,0xDD);___output(ae,0x44);ae->nop+=4; + ___output(ae,0xDD);___output(ae,0x4D);ae->tick+=16;break; + case CRC_IY:___output(ae,0xFD);___output(ae,0x44);ae->nop+=4; + ___output(ae,0xFD);___output(ae,0x4D);ae->tick+=16;break; + default: + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0 && (ae->wl[ae->idx+2].w[3]=='+' || ae->wl[ae->idx+2].w[3]=='-')) { + /* enhanced LD BC,(IX+nn) */ + ___output(ae,0xDD);___output(ae,0x46); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV81); + ___output(ae,0xDD);___output(ae,0x4E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=10;ae->tick+=19;ae->tick+=19; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0 && (ae->wl[ae->idx+2].w[3]=='+' || ae->wl[ae->idx+2].w[3]=='-')) { + /* enhanced LD BC,(IY+nn) */ + ___output(ae,0xFD);___output(ae,0x46); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV81); + ___output(ae,0xFD);___output(ae,0x4E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=10;ae->tick+=19;ae->tick+=19; + } else if (StringIsMem(ae->wl[ae->idx+2].w)) { + ___output(ae,0xED);___output(ae,0x4B); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV16); + ae->nop+=6;ae->tick+=20; + } else { + ___output(ae,0x01); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V16); + ae->nop+=3;ae->tick+=10; + } + } + break; + case CRC_DE: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_BC:___output(ae,0x50);___output(ae,0x59);ae->nop+=2;ae->tick+=8;break; + case CRC_DE:___output(ae,0x52);___output(ae,0x5B);ae->nop+=2;ae->tick+=8;break; + case CRC_HL:___output(ae,0x54);___output(ae,0x5D);ae->nop+=2;ae->tick+=8;break; + /* enhanced LD DE,IX / LD DE,IY */ + case CRC_IX:___output(ae,0xDD);___output(ae,0x54);ae->nop+=4; + ___output(ae,0xDD);___output(ae,0x5D);ae->tick+=16;break; + case CRC_IY:___output(ae,0xFD);___output(ae,0x54);ae->nop+=4; + ___output(ae,0xFD);___output(ae,0x5D);ae->tick+=16;break; + default: + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0 && (ae->wl[ae->idx+2].w[3]=='+' || ae->wl[ae->idx+2].w[3]=='-')) { + /* enhanced LD DE,(IX+nn) */ + ___output(ae,0xDD);___output(ae,0x56); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV81); + ___output(ae,0xDD);___output(ae,0x5E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=10;ae->tick+=19;ae->tick+=19; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0 && (ae->wl[ae->idx+2].w[3]=='+' || ae->wl[ae->idx+2].w[3]=='-')) { + /* enhanced LD DE,(IY+nn) */ + ___output(ae,0xFD);___output(ae,0x56); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV81); + ___output(ae,0xFD);___output(ae,0x5E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=10;ae->tick+=19;ae->tick+=19; + } else if (StringIsMem(ae->wl[ae->idx+2].w)) { + ___output(ae,0xED);___output(ae,0x5B); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV16); + ae->nop+=6;ae->tick+=20; + } else { + ___output(ae,0x11); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V16); + ae->nop+=3;ae->tick+=10; + } + } + break; + case CRC_IX: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + /* enhanced LD IX,BC / LD IX,DE */ + case CRC_BC:___output(ae,0xDD);___output(ae,0x60); + ___output(ae,0xDD);___output(ae,0x69);ae->nop+=4;ae->tick+=16;break; + case CRC_DE:___output(ae,0xDD);___output(ae,0x62); + ___output(ae,0xDD);___output(ae,0x6B);ae->nop+=4;ae->tick+=16;break; + default: + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3) && strncmp(ae->wl[ae->idx+2].w,"(IY",3)) { + if (StringIsMem(ae->wl[ae->idx+2].w)) { + ___output(ae,0xDD);___output(ae,0x2A); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV16); + ae->nop+=6;ae->tick+=20; + } else { + ___output(ae,0xDD);___output(ae,0x21); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV16); + ae->nop+=4;ae->tick+=14; + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD IX,(nn)/BC/DE/nn only\n"); + } + } + break; + case CRC_IY: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + /* enhanced LD IY,BC / LD IY,DE */ + case CRC_BC:___output(ae,0xFD);___output(ae,0x60); + ___output(ae,0xFD);___output(ae,0x69);ae->nop+=4;ae->tick+=16;break; + case CRC_DE:___output(ae,0xFD);___output(ae,0x62); + ___output(ae,0xFD);___output(ae,0x6B);ae->nop+=4;ae->tick+=16;break; + default: + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3) && strncmp(ae->wl[ae->idx+2].w,"(IY",3)) { + if (StringIsMem(ae->wl[ae->idx+2].w)) { + ___output(ae,0xFD);___output(ae,0x2A); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV16); + ae->nop+=6;ae->tick+=20; + } else { + ___output(ae,0xFD);___output(ae,0x21); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV16); + ae->nop+=4;ae->tick+=14; + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD IY,(nn)/BC/DE/nn only\n"); + } + } + break; + case CRC_SP: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_HL:___output(ae,0xF9);ae->nop+=2;ae->tick+=6;break; + case CRC_IX:___output(ae,0xDD);___output(ae,0xF9);ae->nop+=3;ae->tick+=10;break; + case CRC_IY:___output(ae,0xFD);___output(ae,0xF9);ae->nop+=3;ae->tick+=10;break; + default: + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3) && strncmp(ae->wl[ae->idx+2].w,"(IY",3)) { + if (StringIsMem(ae->wl[ae->idx+2].w)) { + ___output(ae,0xED);___output(ae,0x7B); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV16); + ae->nop+=6;ae->tick+=20; + } else { + ___output(ae,0x31); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V16); + ae->nop+=3;ae->tick+=10; + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD SP,(nn)/HL/IX/IY only\n"); + } + } + break; + default: + /* (ix+expression) (iy+expression) (expression) expression */ + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0xDD);___output(ae,0x70);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;ae->tick+=19;break; + case CRC_C:___output(ae,0xDD);___output(ae,0x71);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;ae->tick+=19;break; + case CRC_D:___output(ae,0xDD);___output(ae,0x72);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;ae->tick+=19;break; + case CRC_E:___output(ae,0xDD);___output(ae,0x73);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;ae->tick+=19;break; + case CRC_H:___output(ae,0xDD);___output(ae,0x74);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;ae->tick+=19;break; + case CRC_L:___output(ae,0xDD);___output(ae,0x75);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;ae->tick+=19;break; + case CRC_A:___output(ae,0xDD);___output(ae,0x77);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;ae->tick+=19;break; + case CRC_HL:___output(ae,0xDD);___output(ae,0x74);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV81);___output(ae,0xDD);___output(ae,0x75);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=10;ae->tick+=38;break; + case CRC_DE:___output(ae,0xDD);___output(ae,0x72);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV81);___output(ae,0xDD);___output(ae,0x73);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=10;ae->tick+=38;break; + case CRC_BC:___output(ae,0xDD);___output(ae,0x70);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV81);___output(ae,0xDD);___output(ae,0x71);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=10;ae->tick+=38;break; + default: + if (!StringIsMem(ae->wl[ae->idx+2].w)) { + ___output(ae,0xDD);___output(ae,0x36); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + PushExpression(ae,ae->idx+2,E_EXPRESSION_3V8); + ae->nop+=6;ae->tick+=23; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD (IX+n),n/r only\n"); + } + } + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0xFD);___output(ae,0x70);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;ae->tick+=19;break; + case CRC_C:___output(ae,0xFD);___output(ae,0x71);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;ae->tick+=19;break; + case CRC_D:___output(ae,0xFD);___output(ae,0x72);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;ae->tick+=19;break; + case CRC_E:___output(ae,0xFD);___output(ae,0x73);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;ae->tick+=19;break; + case CRC_H:___output(ae,0xFD);___output(ae,0x74);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;ae->tick+=19;break; + case CRC_L:___output(ae,0xFD);___output(ae,0x75);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;ae->tick+=19;break; + case CRC_A:___output(ae,0xFD);___output(ae,0x77);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;ae->tick+=19;break; + case CRC_HL:___output(ae,0xFD);___output(ae,0x74);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV81);___output(ae,0xFD);___output(ae,0x75);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=10;ae->tick+=38;break; + case CRC_DE:___output(ae,0xFD);___output(ae,0x72);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV81);___output(ae,0xFD);___output(ae,0x73);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=10;ae->tick+=38;break; + case CRC_BC:___output(ae,0xFD);___output(ae,0x70);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV81);___output(ae,0xFD);___output(ae,0x71);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=10;ae->tick+=38;break; + default: + if (!StringIsMem(ae->wl[ae->idx+2].w)) { + ___output(ae,0xFD);___output(ae,0x36); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + PushExpression(ae,ae->idx+2,E_EXPRESSION_3V8); + ae->nop+=6;ae->tick+=23; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD (IX+n),n/r only\n"); + } + } + } else if (StringIsMem(ae->wl[ae->idx+1].w)) { + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_A:___output(ae,0x32);PushExpression(ae,ae->idx+1,E_EXPRESSION_V16);ae->nop+=4;ae->tick+=13;break; + case CRC_BC:___output(ae,0xED);___output(ae,0x43);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV16);ae->nop+=6;ae->tick+=20;break; + case CRC_DE:___output(ae,0xED);___output(ae,0x53);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV16);ae->nop+=6;ae->tick+=20;break; + case CRC_HL:___output(ae,0x22);PushExpression(ae,ae->idx+1,E_EXPRESSION_V16);ae->nop+=5;ae->tick+=16;break; + case CRC_IX:___output(ae,0xDD);___output(ae,0x22);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV16);ae->nop+=6;ae->tick+=20;break; + case CRC_IY:___output(ae,0xFD);___output(ae,0x22);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV16);ae->nop+=6;ae->tick+=20;break; + case CRC_SP:___output(ae,0xED);___output(ae,0x73);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV16);ae->nop+=6;ae->tick+=20;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD (#nnnn),[A,BC,DE,HL,SP,IX,IY] only\n"); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Unknown LD format\n"); + } + break; + } + ae->idx+=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD needs two parameters\n"); + } +} + + +void _RLC(struct s_assenv *ae) { + /* on check qu'il y a un ou deux parametres */ + if (ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_B:___output(ae,0xCB);___output(ae,0x0);ae->nop+=2;ae->tick+=8;break; + case CRC_C:___output(ae,0xCB);___output(ae,0x1);ae->nop+=2;ae->tick+=8;break; + case CRC_D:___output(ae,0xCB);___output(ae,0x2);ae->nop+=2;ae->tick+=8;break; + case CRC_E:___output(ae,0xCB);___output(ae,0x3);ae->nop+=2;ae->tick+=8;break; + case CRC_H:___output(ae,0xCB);___output(ae,0x4);ae->nop+=2;ae->tick+=8;break; + case CRC_L:___output(ae,0xCB);___output(ae,0x5);ae->nop+=2;ae->tick+=8;break; + case CRC_MHL:___output(ae,0xCB);___output(ae,0x6);ae->nop+=4;ae->tick+=15;break; + case CRC_A:___output(ae,0xCB);___output(ae,0x7);ae->nop+=2;ae->tick+=8;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x6); + ae->nop+=7;ae->tick+=23; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x6); + ae->nop+=7;ae->tick+=23; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RLC reg8/(HL)/(IX+n)/(IY+n)\n"); + } + } + ae->idx++; + } else if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD); + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RLC (IX+n),reg8\n"); + } + ___output(ae,0xCB); + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x0);ae->nop+=7;ae->tick+=23;break; + case CRC_C:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x1);ae->nop+=7;ae->tick+=23;break; + case CRC_D:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x2);ae->nop+=7;ae->tick+=23;break; + case CRC_E:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x3);ae->nop+=7;ae->tick+=23;break; + case CRC_H:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x4);ae->nop+=7;ae->tick+=23;break; + case CRC_L:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x5);ae->nop+=7;ae->tick+=23;break; + case CRC_A:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x7);ae->nop+=7;ae->tick+=23;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RLC (IX+n),reg8\n"); + } + ae->idx++; + ae->idx++; + } +} + +void _RRC(struct s_assenv *ae) { + /* on check qu'il y a un ou deux parametres */ + if (ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_B:___output(ae,0xCB);___output(ae,0x8);ae->nop+=2;ae->tick+=8;break; + case CRC_C:___output(ae,0xCB);___output(ae,0x9);ae->nop+=2;ae->tick+=8;break; + case CRC_D:___output(ae,0xCB);___output(ae,0xA);ae->nop+=2;ae->tick+=8;break; + case CRC_E:___output(ae,0xCB);___output(ae,0xB);ae->nop+=2;ae->tick+=8;break; + case CRC_H:___output(ae,0xCB);___output(ae,0xC);ae->nop+=2;ae->tick+=8;break; + case CRC_L:___output(ae,0xCB);___output(ae,0xD);ae->nop+=2;ae->tick+=8;break; + case CRC_MHL:___output(ae,0xCB);___output(ae,0xE);ae->nop+=4;ae->tick+=15;break; + case CRC_A:___output(ae,0xCB);___output(ae,0xF);ae->nop+=2;ae->tick+=8;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0xE); + ae->nop+=7;ae->tick+=23; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0xE);ae->tick+=23; + ae->nop+=7; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RRC reg8/(HL)/(IX+n)/(IY+n)\n"); + } + } + ae->idx++; + } else if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD); + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RRC (IX+n),reg8\n"); + } + ___output(ae,0xCB); + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x8);ae->nop+=7;ae->tick+=23;break; + case CRC_C:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x9);ae->nop+=7;ae->tick+=23;break; + case CRC_D:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0xA);ae->nop+=7;ae->tick+=23;break; + case CRC_E:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0xB);ae->nop+=7;ae->tick+=23;break; + case CRC_H:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0xC);ae->nop+=7;ae->tick+=23;break; + case CRC_L:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0xD);ae->nop+=7;ae->tick+=23;break; + case CRC_A:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0xF);ae->nop+=7;ae->tick+=23;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RRC (IX+n),reg8\n"); + } + ae->idx++; + ae->idx++; + } +} + + +void _RL(struct s_assenv *ae) { + /* on check qu'il y a un ou deux parametres */ + if (ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_BC:___output(ae,0xCB);___output(ae,0x10);___output(ae,0xCB);___output(ae,0x11);ae->nop+=4;ae->tick+=16;break; + case CRC_B:___output(ae,0xCB);___output(ae,0x10);ae->nop+=2;ae->tick+=8;break; + case CRC_C:___output(ae,0xCB);___output(ae,0x11);ae->nop+=2;ae->tick+=8;break; + case CRC_DE:___output(ae,0xCB);___output(ae,0x12);___output(ae,0xCB);___output(ae,0x13);ae->nop+=4;ae->tick+=16;break; + case CRC_D:___output(ae,0xCB);___output(ae,0x12);ae->nop+=2;ae->tick+=8;break; + case CRC_E:___output(ae,0xCB);___output(ae,0x13);ae->nop+=2;ae->tick+=8;break; + case CRC_HL:___output(ae,0xCB);___output(ae,0x14);___output(ae,0xCB);___output(ae,0x15);ae->nop+=4;ae->tick+=16;break; + case CRC_H:___output(ae,0xCB);___output(ae,0x14);ae->nop+=2;ae->tick+=8;break; + case CRC_L:___output(ae,0xCB);___output(ae,0x15);ae->nop+=2;ae->tick+=8;break; + case CRC_MHL:___output(ae,0xCB);___output(ae,0x16);ae->nop+=4;ae->tick+=15;break; + case CRC_A:___output(ae,0xCB);___output(ae,0x17);ae->nop+=2;ae->tick+=8;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x16); + ae->nop+=7;ae->tick+=23; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x16); + ae->nop+=7;ae->tick+=23; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RL reg8/(HL)/(IX+n)/(IY+n)\n"); + } + } + ae->idx++; + } else if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD); + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RL (IX+n),reg8\n"); + } + ___output(ae,0xCB); + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x10);ae->nop+=7;ae->tick+=23;break; + case CRC_C:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x11);ae->nop+=7;ae->tick+=23;break; + case CRC_D:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x12);ae->nop+=7;ae->tick+=23;break; + case CRC_E:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x13);ae->nop+=7;ae->tick+=23;break; + case CRC_H:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x14);ae->nop+=7;ae->tick+=23;break; + case CRC_L:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x15);ae->nop+=7;ae->tick+=23;break; + case CRC_A:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x17);ae->nop+=7;ae->tick+=23;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RL (IX+n),reg8\n"); + } + ae->idx++; + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RL (IX+n),reg8 or RL reg8/(HL)/(IX+n)/(IY+n)\n"); + } +} + +void _RR(struct s_assenv *ae) { + /* on check qu'il y a un ou deux parametres */ + if (ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_BC:___output(ae,0xCB);___output(ae,0x18);___output(ae,0xCB);___output(ae,0x19);ae->nop+=4;ae->tick+=16;break; + case CRC_B:___output(ae,0xCB);___output(ae,0x18);ae->nop+=2;ae->tick+=8;break; + case CRC_C:___output(ae,0xCB);___output(ae,0x19);ae->nop+=2;ae->tick+=8;break; + case CRC_DE:___output(ae,0xCB);___output(ae,0x1A);___output(ae,0xCB);___output(ae,0x1B);ae->nop+=4;ae->tick+=16;break; + case CRC_D:___output(ae,0xCB);___output(ae,0x1A);ae->nop+=2;ae->tick+=8;break; + case CRC_E:___output(ae,0xCB);___output(ae,0x1B);ae->nop+=2;ae->tick+=8;break; + case CRC_HL:___output(ae,0xCB);___output(ae,0x1C);___output(ae,0xCB);___output(ae,0x1D);ae->nop+=4;ae->tick+=16;break; + case CRC_H:___output(ae,0xCB);___output(ae,0x1C);ae->nop+=2;ae->tick+=8;break; + case CRC_L:___output(ae,0xCB);___output(ae,0x1D);ae->nop+=2;ae->tick+=8;break; + case CRC_MHL:___output(ae,0xCB);___output(ae,0x1E);ae->nop+=4;ae->tick+=15;break; + case CRC_A:___output(ae,0xCB);___output(ae,0x1F);ae->nop+=2;ae->tick+=8;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x1E); + ae->nop+=7;ae->tick+=23; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x1E); + ae->nop+=7;ae->tick+=23; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RR reg8/(HL)/(IX+n)/(IY+n)\n"); + } + } + ae->idx++; + } else if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD); + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RR (IX+n),reg8\n"); + } + ___output(ae,0xCB); + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x18);ae->nop+=7;ae->tick+=23;break; + case CRC_C:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x19);ae->nop+=7;ae->tick+=23;break; + case CRC_D:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x1A);ae->nop+=7;ae->tick+=23;break; + case CRC_E:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x1B);ae->nop+=7;ae->tick+=23;break; + case CRC_H:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x1C);ae->nop+=7;ae->tick+=23;break; + case CRC_L:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x1D);ae->nop+=7;ae->tick+=23;break; + case CRC_A:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x1F);ae->nop+=7;ae->tick+=23;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RR (IX+n),reg8\n"); + } + ae->idx++; + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RR (IX+n),reg8 or RR reg8/(HL)/(IX+n)/(IY+n)\n"); + } +} + +void _SLA(struct s_assenv *ae) { + /* on check qu'il y a un ou deux parametres */ + if (ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_BC:___output(ae,0xCB);___output(ae,0x21);___output(ae,0xCB);___output(ae,0x10);ae->nop+=4;ae->tick+=16;break; /* SLA C : RL B */ + case CRC_B:___output(ae,0xCB);___output(ae,0x20);ae->nop+=2;ae->tick+=8;break; + case CRC_C:___output(ae,0xCB);___output(ae,0x21);ae->nop+=2;ae->tick+=8;break; + case CRC_DE:___output(ae,0xCB);___output(ae,0x23);___output(ae,0xCB);___output(ae,0x12);ae->nop+=4;ae->tick+=16;break; /* SLA E : RL D */ + case CRC_D:___output(ae,0xCB);___output(ae,0x22);ae->nop+=2;ae->tick+=8;break; + case CRC_E:___output(ae,0xCB);___output(ae,0x23);ae->nop+=2;ae->tick+=8;break; + case CRC_HL:___output(ae,0xCB);___output(ae,0x25);___output(ae,0xCB);___output(ae,0x14);ae->nop+=4;ae->tick+=16;break; /* SLA L : RL H */ + case CRC_H:___output(ae,0xCB);___output(ae,0x24);ae->nop+=2;ae->tick+=8;break; + case CRC_L:___output(ae,0xCB);___output(ae,0x25);ae->nop+=2;ae->tick+=8;break; + case CRC_MHL:___output(ae,0xCB);___output(ae,0x26);ae->nop+=4;ae->tick+=15;break; + case CRC_A:___output(ae,0xCB);___output(ae,0x27);ae->nop+=2;ae->tick+=8;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x26); + ae->nop+=7;ae->tick+=23; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x26); + ae->nop+=7;ae->tick+=23; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SLA reg8/(HL)/(IX+n)/(IY+n)\n"); + } + } + ae->idx++; + } else if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD); + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SLA (IX+n),reg8\n"); + } + ___output(ae,0xCB); + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x20);ae->nop+=7;ae->tick+=23;break; + case CRC_C:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x21);ae->nop+=7;ae->tick+=23;break; + case CRC_D:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x22);ae->nop+=7;ae->tick+=23;break; + case CRC_E:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x23);ae->nop+=7;ae->tick+=23;break; + case CRC_H:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x24);ae->nop+=7;ae->tick+=23;break; + case CRC_L:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x25);ae->nop+=7;ae->tick+=23;break; + case CRC_A:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x27);ae->nop+=7;ae->tick+=23;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SLA (IX+n),reg8\n"); + } + ae->idx++; + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SLA reg8/(HL)/(IX+n)/(IY+n) or SLA (IX+n),reg8\n"); + } +} + +void _SRA(struct s_assenv *ae) { + /* on check qu'il y a un ou deux parametres */ + if (ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_BC:___output(ae,0xCB);___output(ae,0x28);___output(ae,0xCB);___output(ae,0x19);ae->nop+=4;ae->tick+=16;break; /* SRA B : RR C */ + case CRC_B:___output(ae,0xCB);___output(ae,0x28);ae->nop+=2;ae->tick+=8;break; + case CRC_C:___output(ae,0xCB);___output(ae,0x29);ae->nop+=2;ae->tick+=8;break; + case CRC_DE:___output(ae,0xCB);___output(ae,0x2A);___output(ae,0xCB);___output(ae,0x1B);ae->nop+=4;ae->tick+=16;break; /* SRA D : RR E */ + case CRC_D:___output(ae,0xCB);___output(ae,0x2A);ae->nop+=2;ae->tick+=8;break; + case CRC_E:___output(ae,0xCB);___output(ae,0x2B);ae->nop+=2;ae->tick+=8;break; + case CRC_HL:___output(ae,0xCB);___output(ae,0x2C);___output(ae,0xCB);___output(ae,0x1D);ae->nop+=4;ae->tick+=16;break; /* SRA H : RR L */ + case CRC_H:___output(ae,0xCB);___output(ae,0x2C);ae->nop+=2;ae->tick+=8;break; + case CRC_L:___output(ae,0xCB);___output(ae,0x2D);ae->nop+=2;ae->tick+=8;break; + case CRC_MHL:___output(ae,0xCB);___output(ae,0x2E);ae->nop+=4;ae->tick+=15;break; + case CRC_A:___output(ae,0xCB);___output(ae,0x2F);ae->nop+=2;ae->tick+=8;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x2E); + ae->nop+=7;ae->tick+=23; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x2E); + ae->nop+=7;ae->tick+=23; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SRA reg8/(HL)/(IX+n)/(IY+n)\n"); + } + } + ae->idx++; + } else if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD); + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SRA (IX+n),reg8\n"); + } + ___output(ae,0xCB); + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x28);ae->nop+=7;ae->tick+=23;break; + case CRC_C:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x29);ae->nop+=7;ae->tick+=23;break; + case CRC_D:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x2A);ae->nop+=7;ae->tick+=23;break; + case CRC_E:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x2B);ae->nop+=7;ae->tick+=23;break; + case CRC_H:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x2C);ae->nop+=7;ae->tick+=23;break; + case CRC_L:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x2D);ae->nop+=7;ae->tick+=23;break; + case CRC_A:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x2F);ae->nop+=7;ae->tick+=23;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SRA (IX+n),reg8\n"); + } + ae->idx++; + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SRA reg8/(HL)/(IX+n)/(IY+n) or SRA (IX+n),reg8\n"); + } +} + + +void _SLL(struct s_assenv *ae) { + /* on check qu'il y a un ou deux parametres */ + if (ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_BC:___output(ae,0xCB);___output(ae,0x31);___output(ae,0xCB);___output(ae,0x10);ae->nop+=4;ae->tick+=16;break; /* SLL C : RL B */ + case CRC_B:___output(ae,0xCB);___output(ae,0x30);ae->nop+=2;ae->tick+=8;break; + case CRC_C:___output(ae,0xCB);___output(ae,0x31);ae->nop+=2;ae->tick+=8;break; + case CRC_DE:___output(ae,0xCB);___output(ae,0x33);___output(ae,0xCB);___output(ae,0x12);ae->nop+=4;ae->tick+=16;break; /* SLL E : RL D */ + case CRC_D:___output(ae,0xCB);___output(ae,0x32);ae->nop+=2;ae->tick+=8;break; + case CRC_E:___output(ae,0xCB);___output(ae,0x33);ae->nop+=2;ae->tick+=8;break; + case CRC_HL:___output(ae,0xCB);___output(ae,0x35);___output(ae,0xCB);___output(ae,0x14);ae->nop+=4;ae->tick+=16;break; /* SLL L : RL H */ + case CRC_H:___output(ae,0xCB);___output(ae,0x34);ae->nop+=2;ae->tick+=8;break; + case CRC_L:___output(ae,0xCB);___output(ae,0x35);ae->nop+=2;ae->tick+=8;break; + case CRC_MHL:___output(ae,0xCB);___output(ae,0x36);ae->nop+=4;ae->tick+=15;break; + case CRC_A:___output(ae,0xCB);___output(ae,0x37);ae->nop+=2;ae->tick+=8;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x36); + ae->nop+=7;ae->tick+=23; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x36); + ae->nop+=7;ae->tick+=23; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SLL reg8/(HL)/(IX+n)/(IY+n)\n"); + } + } + ae->idx++; + } else if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD); + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SLL (IX+n),reg8\n"); + } + ___output(ae,0xCB); + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x30);ae->nop+=7;ae->tick+=23;break; + case CRC_C:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x31);ae->nop+=7;ae->tick+=23;break; + case CRC_D:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x32);ae->nop+=7;ae->tick+=23;break; + case CRC_E:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x33);ae->nop+=7;ae->tick+=23;break; + case CRC_H:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x34);ae->nop+=7;ae->tick+=23;break; + case CRC_L:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x35);ae->nop+=7;ae->tick+=23;break; + case CRC_A:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x37);ae->nop+=7;ae->tick+=23;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SLL (IX+n),reg8\n"); + } + ae->idx++; + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SLL reg8/(HL)/(IX+n)/(IY+n) or SLL (IX+n),reg8\n"); + } +} + +void _SRL(struct s_assenv *ae) { + /* on check qu'il y a un ou deux parametres */ + if (ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_BC:___output(ae,0xCB);___output(ae,0x38);___output(ae,0xCB);___output(ae,0x19);ae->nop+=4;ae->tick+=16;break; /* SRL B : RR C */ + case CRC_B:___output(ae,0xCB);___output(ae,0x38);ae->nop+=2;ae->tick+=8;break; + case CRC_C:___output(ae,0xCB);___output(ae,0x39);ae->nop+=2;ae->tick+=8;break; + case CRC_DE:___output(ae,0xCB);___output(ae,0x3A);___output(ae,0xCB);___output(ae,0x1B);ae->nop+=4;ae->tick+=16;break; /* SRL D : RR E */ + case CRC_D:___output(ae,0xCB);___output(ae,0x3A);ae->nop+=2;ae->tick+=8;break; + case CRC_E:___output(ae,0xCB);___output(ae,0x3B);ae->nop+=2;ae->tick+=8;break; + case CRC_HL:___output(ae,0xCB);___output(ae,0x3C);___output(ae,0xCB);___output(ae,0x1D);ae->nop+=4;ae->tick+=16;break; /* SRL H : RR L */ + case CRC_H:___output(ae,0xCB);___output(ae,0x3C);ae->nop+=2;ae->tick+=8;break; + case CRC_L:___output(ae,0xCB);___output(ae,0x3D);ae->nop+=2;ae->tick+=8;break; + case CRC_MHL:___output(ae,0xCB);___output(ae,0x3E);ae->nop+=4;ae->tick+=15;break; + case CRC_A:___output(ae,0xCB);___output(ae,0x3F);ae->nop+=2;ae->tick+=8;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x3E); + ae->nop+=7;ae->tick+=23; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x3E); + ae->nop+=7;ae->tick+=23; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SRL reg8/(HL)/(IX+n)/(IY+n)\n"); + } + } + ae->idx++; + } else if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD); + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SRL (IX+n),reg8\n"); + } + ___output(ae,0xCB); + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x38);ae->nop+=7;ae->tick+=23;break; + case CRC_C:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x39);ae->nop+=7;ae->tick+=23;break; + case CRC_D:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x3A);ae->nop+=7;ae->tick+=23;break; + case CRC_E:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x3B);ae->nop+=7;ae->tick+=23;break; + case CRC_H:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x3C);ae->nop+=7;ae->tick+=23;break; + case CRC_L:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x3D);ae->nop+=7;ae->tick+=23;break; + case CRC_A:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x3F);ae->nop+=7;ae->tick+=23;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SRL (IX+n),reg8\n"); + } + ae->idx++; + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SRL reg8/(HL)/(IX+n)/(IY+n) or SRL (IX+n),reg8\n"); + } +} + + +void _BIT(struct s_assenv *ae) { + int o; + /* on check qu'il y a deux ou trois parametres + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + o=RoundComputeExpressionCore(ae,ae->wl[ae->idx+1].w,ae->codeadr,0);*/ + + o=0; + if (o<0 || o>7) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is BIT ,... (%d)\n",o); + } else { + o=0x40+o*8; + if (ae->wl[ae->idx+1].t==0 && ae->wl[ae->idx+2].t==1) { + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x0+o);ae->nop+=2;ae->tick+=8;break; + case CRC_C:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x1+o);ae->nop+=2;ae->tick+=8;break; + case CRC_D:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x2+o);ae->nop+=2;ae->tick+=8;break; + case CRC_E:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x3+o);ae->nop+=2;ae->tick+=8;break; + case CRC_H:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x4+o);ae->nop+=2;ae->tick+=8;break; + case CRC_L:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x5+o);ae->nop+=2;ae->tick+=8;break; + case CRC_MHL:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x6+o);ae->nop+=3;ae->tick+=12;break; + case CRC_A:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x7+o);ae->nop+=2;ae->tick+=8;break; + default: + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0xCB); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x6+o); + ae->nop+=6;ae->tick+=20; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0xCB); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x6+o); + ae->nop+=6;ae->tick+=20; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is BIT n,reg8/(HL)/(IX+n)/(IY+n)\n"); + } + } + ae->idx+=2; + } else if (!ae->wl[ae->idx+1].t && !ae->wl[ae->idx+2].t && ae->wl[ae->idx+3].t==1) { + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD); + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is BIT (IX+n),reg8\n"); + } + ___output(ae,0xCB); + switch (GetCRC(ae->wl[ae->idx+3].w)) { + case CRC_B:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x0+o);ae->nop+=6;ae->tick+=20;break; + case CRC_C:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x1+o);ae->nop+=6;ae->tick+=20;break; + case CRC_D:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x2+o);ae->nop+=6;ae->tick+=20;break; + case CRC_E:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x3+o);ae->nop+=6;ae->tick+=20;break; + case CRC_H:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x4+o);ae->nop+=6;ae->tick+=20;break; + case CRC_L:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x5+o);ae->nop+=6;ae->tick+=20;break; + case CRC_A:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x7+o);ae->nop+=6;ae->tick+=20;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is BIT n,(IX+n),reg8\n"); + } + ae->idx+=3; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is BIT n,reg8/(HL)/(IX+n)[,reg8]/(IY+n)[,reg8]\n"); + } + } +} + +void _RES(struct s_assenv *ae) { + int o; + /* on check qu'il y a deux ou trois parametres + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + o=RoundComputeExpressionCore(ae,ae->wl[ae->idx+1].w,ae->codeadr,0); */ + o=0; + if (o<0 || o>7) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RES ,... (%d)\n",o); + } else { + o=0x80+o*8; + if (ae->wl[ae->idx+1].t==0 && ae->wl[ae->idx+2].t==1) { + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x0+o);ae->nop+=2;ae->tick+=8;break; + case CRC_C:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x1+o);ae->nop+=2;ae->tick+=8;break; + case CRC_D:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x2+o);ae->nop+=2;ae->tick+=8;break; + case CRC_E:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x3+o);ae->nop+=2;ae->tick+=8;break; + case CRC_H:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x4+o);ae->nop+=2;ae->tick+=8;break; + case CRC_L:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x5+o);ae->nop+=2;ae->tick+=8;break; + case CRC_MHL:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x6+o);ae->nop+=4;ae->tick+=15;break; + case CRC_A:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x7+o);ae->nop+=2;ae->tick+=8;break; + default: + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0xCB); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x6+o); + ae->nop+=7;ae->tick+=23; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0xCB); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x6+o); + ae->nop+=7;ae->tick+=23; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RES n,reg8/(HL)/(IX+n)/(IY+n)\n"); + } + } + ae->idx+=2; + } else if (!ae->wl[ae->idx+1].t && !ae->wl[ae->idx+2].t && ae->wl[ae->idx+3].t==1) { + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD); + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RES n,(IX+n),reg8\n"); + } + ___output(ae,0xCB); + switch (GetCRC(ae->wl[ae->idx+3].w)) { + case CRC_B:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x0+o);ae->nop+=7;ae->tick+=23;break; + case CRC_C:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x1+o);ae->nop+=7;ae->tick+=23;break; + case CRC_D:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x2+o);ae->nop+=7;ae->tick+=23;break; + case CRC_E:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x3+o);ae->nop+=7;ae->tick+=23;break; + case CRC_H:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x4+o);ae->nop+=7;ae->tick+=23;break; + case CRC_L:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x5+o);ae->nop+=7;ae->tick+=23;break; + case CRC_A:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x7+o);ae->nop+=7;ae->tick+=23;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RES n,(IX+n),reg8\n"); + } + ae->idx+=3; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RES n,reg8/(HL)/(IX+n)[,reg8]/(IY+n)[,reg8]\n"); + } + } +} + +void _SET(struct s_assenv *ae) { + int o; + /* on check qu'il y a deux ou trois parametres + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + o=RoundComputeExpressionCore(ae,ae->wl[ae->idx+1].w,ae->codeadr,0); */ + o=0; + if (o<0 || o>7) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SET ,... (%d)\n",o); + } else { + o=0xC0+o*8; + if (ae->wl[ae->idx+1].t==0 && ae->wl[ae->idx+2].t==1) { + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x0+o);ae->nop+=2;ae->tick+=8;break; + case CRC_C:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x1+o);ae->nop+=2;ae->tick+=8;break; + case CRC_D:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x2+o);ae->nop+=2;ae->tick+=8;break; + case CRC_E:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x3+o);ae->nop+=2;ae->tick+=8;break; + case CRC_H:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x4+o);ae->nop+=2;ae->tick+=8;break; + case CRC_L:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x5+o);ae->nop+=2;ae->tick+=8;break; + case CRC_MHL:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x6+o);ae->nop+=4;ae->tick+=15;break; + case CRC_A:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x7+o);ae->nop+=2;ae->tick+=8;break; + default: + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0xCB); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x6+o); + ae->nop+=7;ae->tick+=23; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0xCB); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x6+o); + ae->nop+=7;ae->tick+=23; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SET n,reg8/(HL)/(IX+n)/(IY+n)\n"); + } + } + ae->idx+=2; + } else if (!ae->wl[ae->idx+1].t && !ae->wl[ae->idx+2].t && ae->wl[ae->idx+3].t==1) { + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD); + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SET n,(IX+n),reg8\n"); + } + ___output(ae,0xCB); + switch (GetCRC(ae->wl[ae->idx+3].w)) { + case CRC_B:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x0+o);ae->nop+=7;ae->tick+=23;break; + case CRC_C:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x1+o);ae->nop+=7;ae->tick+=23;break; + case CRC_D:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x2+o);ae->nop+=7;ae->tick+=23;break; + case CRC_E:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x3+o);ae->nop+=7;ae->tick+=23;break; + case CRC_H:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x4+o);ae->nop+=7;ae->tick+=23;break; + case CRC_L:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x5+o);ae->nop+=7;ae->tick+=23;break; + case CRC_A:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x7+o);ae->nop+=7;ae->tick+=23;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SET n,(IX+n),reg8\n"); + } + ae->idx+=3; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SET n,reg8/(HL)/(IX+n)[,reg8]/(IY+n)[,reg8]\n"); + } + } +} + +void _DEFS(struct s_assenv *ae) { + int i,r,v; + if (ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Syntax is DEFS repeat,value or DEFS repeat\n"); + } else do { + ae->idx++; + if (!ae->wl[ae->idx].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); /* doing FastTranslate but not a complete evaluation */ + r=RoundComputeExpressionCore(ae,ae->wl[ae->idx].w,ae->codeadr,0); + if (r<0) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFS size must be greater or equal to zero\n"); + } + for (i=0;iidx+1,E_EXPRESSION_0V8); + ae->nop+=1; + } + ae->idx++; + } else if (ae->wl[ae->idx].t==1) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + r=RoundComputeExpressionCore(ae,ae->wl[ae->idx].w,ae->codeadr,0); + v=0; + if (r<0) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFS size must be greater or equal to zero\n"); + } + for (i=0;inop+=1; + } + } + } while (!ae->wl[ae->idx].t); +} + +void _DEFS_struct(struct s_assenv *ae) { + int i,r,v; + if (ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Syntax is DEFS repeat,value or DEFS repeat\n"); + } else do { + ae->idx++; + if (!ae->wl[ae->idx].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + r=RoundComputeExpressionCore(ae,ae->wl[ae->idx].w,ae->codeadr,0); + v=RoundComputeExpressionCore(ae,ae->wl[ae->idx+1].w,ae->codeadr,0); + if (r<0) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFS size must be greater or equal to zero\n"); + } + for (i=0;inop+=1; + } + ae->idx++; + } else if (ae->wl[ae->idx].t==1) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + r=RoundComputeExpressionCore(ae,ae->wl[ae->idx].w,ae->codeadr,0); + v=0; + if (r<0) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFS size must be greater or equal to zero\n"); + } + for (i=0;inop+=1; + } + } + } while (!ae->wl[ae->idx].t); +} + +void _STR(struct s_assenv *ae) { + unsigned char c; + int i,tquote; + + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + if ((tquote=StringIsQuote(ae->wl[ae->idx].w))!=0) { + i=1; + while (ae->wl[ae->idx].w[i] && ae->wl[ae->idx].w[i]!=tquote) { + if (ae->wl[ae->idx].w[i]=='\\') { + i++; + /* no conversion on escaped chars */ + c=ae->wl[ae->idx].w[i]; + switch (c) { + case 'b':c='\b';break; + case 'v':c='\v';break; + case 'f':c='\f';break; + case '0':c='\0';break; + case 'r':c='\r';break; + case 'n':c='\n';break; + case 't':c='\t';break; + default:break; + } + if (ae->wl[ae->idx].w[i+1]!=tquote) { + ___output(ae,c); + } else { + ___output(ae,c|0x80); + } + } else { + /* charset conversion on the fly */ + if (ae->wl[ae->idx].w[i+1]!=tquote) { + ___output(ae,ae->charset[((unsigned int)ae->wl[ae->idx].w[i])&0xFF]); + } else { + ___output(ae,ae->charset[((unsigned int)ae->wl[ae->idx].w[i]|0x80)&0xFF]); + } + } + + i++; + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"STR handle only quoted strings!\n"); + } + } while (ae->wl[ae->idx].t==0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"STR needs one or more quotes parameters\n"); + } +} + +/* Microsoft IEEE-754 40bits float value */ +void _DEFF(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + PushExpression(ae,ae->idx,E_EXPRESSION_0VRMike); + } while (ae->wl[ae->idx].t==0); + } else { + if (ae->getstruct) { + ___output(ae,0);___output(ae,0);___output(ae,0);___output(ae,0);___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFF needs one or more parameters\n"); + } + } +} +void _DEFF_struct(struct s_assenv *ae) { + unsigned char *rc; + double v; + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + /* conversion des symboles connus */ + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + /* calcul de la valeur définitive de l'expression */ + v=ComputeExpressionCore(ae,ae->wl[ae->idx].w,ae->outputadr,0); + /* conversion en réel Amsdos */ + rc=__internal_MakeRosoftREAL(ae,v,0); + ___output(ae,rc[0]);___output(ae,rc[1]);___output(ae,rc[2]);___output(ae,rc[3]);___output(ae,rc[4]); + } while (ae->wl[ae->idx].t==0); + } else { + if (ae->getstruct) { + ___output(ae,0);___output(ae,0);___output(ae,0);___output(ae,0);___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFF needs one or more parameters\n"); + } + } +} + + +void _DEFR(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + PushExpression(ae,ae->idx,E_EXPRESSION_0VR); + } while (ae->wl[ae->idx].t==0); + } else { + if (ae->getstruct) { + ___output(ae,0);___output(ae,0);___output(ae,0);___output(ae,0);___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFR needs one or more parameters\n"); + } + } +} +void _DEFR_struct(struct s_assenv *ae) { + unsigned char *rc; + double v; + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + /* conversion des symboles connus */ + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + /* calcul de la valeur définitive de l'expression */ + v=ComputeExpressionCore(ae,ae->wl[ae->idx].w,ae->outputadr,0); + /* conversion en réel Amsdos */ + rc=__internal_MakeAmsdosREAL(ae,v,0); + ___output(ae,rc[0]);___output(ae,rc[1]);___output(ae,rc[2]);___output(ae,rc[3]);___output(ae,rc[4]); + } while (ae->wl[ae->idx].t==0); + } else { + if (ae->getstruct) { + ___output(ae,0);___output(ae,0);___output(ae,0);___output(ae,0);___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFR needs one or more parameters\n"); + } + } +} + +void _DEFB(struct s_assenv *ae) { + int i,tquote; + unsigned char c; + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + if ((tquote=StringIsQuote(ae->wl[ae->idx].w))!=0) { + i=1; + while (ae->wl[ae->idx].w[i] && ae->wl[ae->idx].w[i]!=tquote) { + if (ae->wl[ae->idx].w[i]=='\\') { + i++; + /* no conversion on escaped chars */ + c=ae->wl[ae->idx].w[i]; + switch (c) { + case 'e':___output(ae,0x1B);break; + case 'a':___output(ae,0x07);break; // alarm + case 'b':___output(ae,'\b');break; + case 'v':___output(ae,'\v');break; // v-tab + case 'f':___output(ae,'\f');break; // feed + case '0':___output(ae,'\0');break; + case 'r':___output(ae,'\r');break; // return + case 'n':___output(ae,'\n');break; // carriage-return + case 't':___output(ae,'\t');break; // tab + default: + ___output(ae,c); + } + ae->nop+=1; + } else { + /* charset conversion on the fly */ + ___output(ae,ae->charset[(unsigned int)(ae->wl[ae->idx].w[i]&0xFF)]); + ae->nop+=1; + } + i++; + } + } else { + PushExpression(ae,ae->idx,E_EXPRESSION_0V8); + ae->nop+=1; + } + } while (ae->wl[ae->idx].t==0); + } else { + if (ae->getstruct) { + ___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFB needs one or more parameters\n"); + } + } +} +void _DEFB_struct(struct s_assenv *ae) { + int i,tquote; + unsigned char c; + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + if ((tquote=StringIsQuote(ae->wl[ae->idx].w))!=0) { + i=1; + while (ae->wl[ae->idx].w[i] && ae->wl[ae->idx].w[i]!=tquote) { + if (ae->wl[ae->idx].w[i]=='\\') { + i++; + /* no conversion on escaped chars */ + c=ae->wl[ae->idx].w[i]; + switch (c) { + case 'b':___output(ae,'\b');break; + case 'v':___output(ae,'\v');break; + case 'f':___output(ae,'\f');break; + case '0':___output(ae,'\0');break; + case 'r':___output(ae,'\r');break; + case 'n':___output(ae,'\n');break; + case 't':___output(ae,'\t');break; + default: + ___output(ae,c); + ae->nop+=1; + } + } else { + /* charset conversion on the fly */ + ___output(ae,ae->charset[(unsigned int)ae->wl[ae->idx].w[i]&0xFF]); + ae->nop+=1; + } + i++; + } + } else { + int v; + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + v=RoundComputeExpressionCore(ae,ae->wl[ae->idx].w,ae->outputadr,0); + ___output(ae,v); + ae->nop+=1; + } + } while (ae->wl[ae->idx].t==0); + } else { + if (ae->getstruct) { + ___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFB needs one or more parameters\n"); + } + } +} + +void _DEFW(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + PushExpression(ae,ae->idx,E_EXPRESSION_0V16); + } while (ae->wl[ae->idx].t==0); + } else { + if (ae->getstruct) { + ___output(ae,0);___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFW needs one or more parameters\n"); + } + } +} + +void _DEFW_struct(struct s_assenv *ae) { + int v; + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + v=RoundComputeExpressionCore(ae,ae->wl[ae->idx].w,ae->outputadr,0); + ___output(ae,v&0xFF);___output(ae,(v>>8)&0xFF); + } while (ae->wl[ae->idx].t==0); + } else { + if (ae->getstruct) { + ___output(ae,0);___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFW needs one or more parameters\n"); + } + } +} + +void _DEFI(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + PushExpression(ae,ae->idx,E_EXPRESSION_0V32); + } while (ae->wl[ae->idx].t==0); + } else { + if (ae->getstruct) { + ___output(ae,0);___output(ae,0);___output(ae,0);___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFI needs one or more parameters\n"); + } + } +} + +void _DEFI_struct(struct s_assenv *ae) { + int v; + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + v=RoundComputeExpressionCore(ae,ae->wl[ae->idx].w,ae->outputadr,0); + ___output(ae,v&0xFF);___output(ae,(v>>8)&0xFF);___output(ae,(v>>16)&0xFF);___output(ae,(v>>24)&0xFF); + } while (ae->wl[ae->idx].t==0); + } else { + if (ae->getstruct) { + ___output(ae,0);___output(ae,0);___output(ae,0);___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFI needs one or more parameters\n"); + } + } +} + +void _DEFB_as80(struct s_assenv *ae) { + int i,tquote; + int modadr=0; + + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + if ((tquote=StringIsQuote(ae->wl[ae->idx].w))!=0) { + i=1; + while (ae->wl[ae->idx].w[i] && ae->wl[ae->idx].w[i]!=tquote) { + if (ae->wl[ae->idx].w[i]=='\\') i++; + /* charset conversion on the fly */ + ___output(ae,ae->charset[(unsigned int)ae->wl[ae->idx].w[i]&0xFF]); + ae->nop+=1; + ae->codeadr--;modadr++; + i++; + } + } else { + PushExpression(ae,ae->idx,E_EXPRESSION_0V8); + ae->codeadr--;modadr++; + ae->nop+=1; + } + } while (ae->wl[ae->idx].t==0); + ae->codeadr+=modadr; + } else { + if (ae->getstruct) { + ___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFB needs one or more parameters\n"); + } + } +} + +void _DEFW_as80(struct s_assenv *ae) { + int modadr=0; + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + PushExpression(ae,ae->idx,E_EXPRESSION_0V16); + ae->codeadr-=2;modadr+=2; + } while (ae->wl[ae->idx].t==0); + ae->codeadr+=modadr; + } else { + if (ae->getstruct) { + ___output(ae,0);___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFW needs one or more parameters\n"); + } + } +} + +void _DEFI_as80(struct s_assenv *ae) { + int modadr=0; + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + PushExpression(ae,ae->idx,E_EXPRESSION_0V32); + ae->codeadr-=4;modadr+=4; + } while (ae->wl[ae->idx].t==0); + ae->codeadr+=modadr; + } else { + if (ae->getstruct) { + ___output(ae,0);___output(ae,0);___output(ae,0);___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFI needs one or more parameters\n"); + } + } +} +#if 0 +void _DEFSTR(struct s_assenv *ae) { + int i,tquote; + unsigned char c; + if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + if (StringIsQuote(ae->wl[ae->idx+1].w) && StringIsQuote(ae->wl[ae->idx+2].w)) { + i=1; + while (ae->wl[ae->idx].w[i] && ae->wl[ae->idx].w[i]!=tquote) { + if (ae->wl[ae->idx].w[i]=='\\') { + i++; + /* no conversion on escaped chars */ + c=ae->wl[ae->idx].w[i]; + switch (c) { + case 'b':___output(ae,'\b');break; + case 'v':___output(ae,'\v');break; + case 'f':___output(ae,'\f');break; + case '0':___output(ae,'\0');break; + case 'r':___output(ae,'\r');break; + case 'n':___output(ae,'\n');break; + case 't':___output(ae,'\t');break; + default: + ___output(ae,c); + } + } else { + /* charset conversion on the fly */ + ___output(ae,ae->charset[(int)ae->wl[ae->idx].w[i]]); + } + i++; + } + } + ae->idx+=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFSTR needs two parameters\n"); + } +} +#endif + +#undef FUNC +#define FUNC "Import/Export CORE" + +// symbol export +void __SYMBOL(struct s_assenv *ae) { +} + +// external symbol import => declare one or more new external variables +void __EXTERNAL(struct s_assenv *ae) { + struct s_external zexternal={0}; + + while (!ae->wl[ae->idx].t) { + ExpressionSetDicoVar(ae,ae->wl[ae->idx+1].w,0.0,1); + zexternal.name=TxtStrDup(ae->wl[ae->idx+1].w); + zexternal.crc=GetCRC(zexternal.name); + ObjectArrayAddDynamicValueConcat((void**)&ae->external,&ae->nexternal,&ae->mexternal,&zexternal,sizeof(struct s_external)); + ae->idx++; + } +} + +// procedure export => tag and declare a label for export +void __PROCEDURE(struct s_assenv *ae) { + char *dupname; + int cpt=1; + while (!ae->wl[ae->idx].t) { + ae->idx++; + /* store procedure label */ + dupname=TxtStrDup(ae->wl[ae->idx].w); + ObjectArrayAddDynamicValueConcat((void**)&ae->procedurename,&ae->nprocedurename,&ae->mprocedurename,&dupname,sizeof(char *)); + /* push label as usual */ + PushLabel(ae); + if (cpt>1) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: PROCEDURE directive is not supposed to declare more than one label\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + if (ae->erronwarn) MaxError(ae); + } + } + cpt++; + } +} + +void __ENDPROC(struct s_assenv *ae) { +} + + + + +#undef FUNC +#define FUNC "Directive CORE" + +void __internal_UpdateLZBlockIfAny(struct s_assenv *ae) { + /* if there was a crunched block opened in the previous bank */ + ae->lz=-1; +} + + +void __AMSDOS(struct s_assenv *ae) { + ae->amsdos=1; +} + +void __internal_EXPORT(struct s_assenv *ae, int exportval) { + struct s_label *curlabel; + struct s_expr_dico *curdic; + int ialias,crc,freeflag; + char *localname; + + if (ae->wl[ae->idx].t) { + /* without parameter enable/disable export */ + ae->autorise_export=exportval; + } else while (!ae->wl[ae->idx].t) { + ae->idx++; + freeflag=0; + + /* local label */ + if (ae->wl[ae->idx].w[0]=='.' && ae->lastgloballabel) { + localname=MemMalloc(strlen(ae->wl[ae->idx].w)+1+ae->lastgloballabellen); + sprintf(localname,"%s%s",ae->lastgloballabel,ae->wl[ae->idx].w); + freeflag=1; + } else { + localname=ae->wl[ae->idx].w; + } + crc=GetCRC(localname); + + if ((curlabel=SearchLabel(ae,localname,crc))!=NULL) { + curlabel->autorise_export=exportval; + ae->label[curlabel->backidx].autorise_export=exportval; + } else { + if ((curdic=SearchDico(ae,ae->wl[ae->idx].w,crc))!=NULL) { + curdic->autorise_export=exportval; + } else { + if ((ialias=SearchAlias(ae,crc,ae->wl[ae->idx].w))!=-1) { + ae->alias[ialias].autorise_export=exportval; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"(E)NOEXPORT did not found [%s] in variables, labels or aliases\n",ae->wl[ae->idx].w); + } + } + } + if (freeflag) MemFree(localname); + } +} +void __NOEXPORT(struct s_assenv *ae) { + __internal_EXPORT(ae,0); +} +void __ENOEXPORT(struct s_assenv *ae) { + __internal_EXPORT(ae,1); +} + +void __BUILDOBJ(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BUILDOBJ does not need a parameter\n"); + } + ae->buildobj=1; +} +void __BUILDZX(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BUILDZX does not need a parameter\n"); + } + if (!ae->forcesnapshot && !ae->forcetape && !ae->forcecpr && !ae->forceROM) { + ae->forcesnapshot=1; + ae->forcezx=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot select ZX output when already in Amstrad ROM/cartridge/snapshot/tape output\n"); + } +} +void __BUILDCPR(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1 && strcmp(ae->wl[ae->idx+1].w,"EXTENDED")==0) { + ae->extendedCPR=1; + } else if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BUILDCPR unknown parameter\n"); + } + if (!ae->forcesnapshot && !ae->forcetape && !ae->forcezx && !ae->forceROM) { + ae->forcecpr=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot select Amstrad cartridge output when already in ZX/ROM/snapshot/tape output\n"); + } +} +void __BUILDROM(struct s_assenv *ae) { + if (!ae->forcesnapshot && !ae->forcetape && !ae->forcezx && !ae->forcecpr) { + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t) { + if (strcmp(ae->wl[ae->idx+1].w,"CONCAT")==0) { + ae->forceROMconcat=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"usage is BUILDROM [CONCAT]\n"); + } + } + ae->forceROM=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot select ROM output when already in ZX/cartridge/snapshot/tape output\n"); + } +} + + +void __SNAPINIT(struct s_assenv *ae) { + unsigned char *dataout; + unsigned char *snapdata; + int src,idx,rep,i,srcmax; + int chunksize; + int version,size; + int snapsize; + int slot; + // integration + char *newfilename=NULL; + int fileok=0; + + if (!ae->forcecpr && !ae->forcetape && !ae->forcezx && !ae->forceROM) { + // automatic BUILDSNA + ae->forcesnapshot=1; + } + + if (!ae->wl[ae->idx].t) { + if (!StringIsQuote(ae->wl[ae->idx+1].w)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SNAPINIT needs a snapshot filename to proceed\n"); + return; + } else { + newfilename=TxtStrDup(ae->wl[ae->idx+1].w+1); // skip first quote + newfilename[strlen(newfilename)-1]=0; // remove last quote + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SNAPINIT needs a snapshot filename to proceed\n"); + return; + } + + /* Where is the file to load? */ + if (!FileExists(newfilename)) { + int ilookfile; + char *filename_toread; + + /* on cherche dans les include */ + for (ilookfile=0;ilookfileipath && !fileok;ilookfile++) { + filename_toread=MergePath(ae,ae->includepath[ilookfile],newfilename); + if (FileExists(filename_toread)) { + fileok=1; + MemFree(newfilename); + newfilename=TxtStrDup(filename_toread); // Merge renvoie un static + } + } + } else { + fileok=1; + } + + if (fileok) { + snapsize=FileGetSize(newfilename); + snapdata=MemMalloc(snapsize); + if (FileReadBinary(newfilename,(char*)snapdata,snapsize)!=snapsize) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"read error on file [%s]\n",newfilename); + MemFree(newfilename); + MemFree(snapdata); + return; + } + FileReadBinaryClose(newfilename); + + if (snapsize<0x100) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"file [%s] seems too small to be a snapshot\n",newfilename); + } else if (snapdata[0]!='M' || snapdata[1]!='V' || snapdata[2]!=' ' || snapdata[3]!='-' || snapdata[4]!=' ' || snapdata[5]!='S' || snapdata[6]!='N' || snapdata[7]!='A') { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"file [%s] invalid snapshot header\n",newfilename); + } else { + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"file [%s] not found!\n",newfilename); + return; + } + + // data extraction + size=snapdata[0x6B]*1024; + src=0x100; + switch (snapdata[0x6B]) { + default: + case 0: + if (snapdata[16]<3) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"file [%s] empty snapshot v2\n",newfilename); + snapsize=0; + } + break; + case 64: + if (snapsize>=size+0x100) { + memcpy(ae->mem[0],snapdata+0x100,65536); + src+=65536; + ae->snapRAMsize=4; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"file [%s] snapshot v2 inconsistency (supposed to be 64k)\n",newfilename); + snapsize=0; + } + break; + case 128: + if (snapsize>=size+0x100) { + memcpy(ae->mem[0],snapdata+0x100,65536); + memcpy(ae->mem[4],snapdata+0x100+65536,65536); + src+=65536*2; + ae->snapRAMsize=8; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"file [%s] snapshot v2 inconsistency (supposed to be 128k)\n",newfilename); + snapsize=0; + } + break; + } + + // raw copy of header for output (check for v2 or v3 ?) + memcpy(&ae->snapshot,snapdata,0x100); + if (ae->snapshot.version<2) { + rasm_printf(ae,KWARNING"[%s:%d] early version of snapshot, upgrading to V2, you may need to use SNASET to get a proper snapshot\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + ae->snapshot.version=2; + } + + while (src+8snapsize) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"file [%s] invalid chunk in snapshot (overrun) chunksize=%d\n",newfilename,chunksize); + break; + } + + dataout=ae->mem[slot*4]; + + if (slot*4+4>ae->snapRAMsize) ae->snapRAMsize=slot*4+4; + + while (idx<65536 && srcwl[ae->idx].l,"file [%s] invalid chunk in snapshot (overrun)\n",newfilename); + break; + } + } else { + // skip non memory chunk + src+=8+chunksize; + } + } + // replicate bankset in memory to be ok with bankset rebuilding + memcpy(ae->mem[1],ae->mem[0],65536); + memcpy(ae->mem[2],ae->mem[0],65536); + memcpy(ae->mem[3],ae->mem[0],65536); + memcpy(ae->mem[5],ae->mem[4],65536); + memcpy(ae->mem[6],ae->mem[4],65536); + memcpy(ae->mem[7],ae->mem[4],65536); + MemFree(newfilename); + MemFree(snapdata); +} + + +void __BUILDSNA(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + if (strcmp(ae->wl[ae->idx+1].w,"V2")==0) { + ae->snapshot.version=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BUILDSNA unrecognized option\n"); + } + } + if (!ae->forcecpr && !ae->forcetape && !ae->forcezx && !ae->forceROM) { + ae->forcesnapshot=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot select snapshot output when already in ZX/ROM/cartridge/tape output\n"); + } +} +void __BUILDTAPE(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BUILDTAPE does not need a parameter\n"); + } + if (!ae->forcesnapshot && !ae->forcecpr && !ae->forcezx && !ae->forceROM) { + ae->forcetape=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot select tape output when already in ZX/ROM/snapshot/cartridge output\n"); + } +} + + +void __LZSA1(struct s_assenv *ae) { + struct s_lz_section curlz={0}; + + if (!ae->wl[ae->idx].t) { + ae->idx++; + curlz.minmatch=atoi(ae->wl[ae->idx].w); + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LZSA1 directive may only have 1 parameter\n"); + } + } + #ifdef NO_3RD_PARTIES + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use 3rd parties cruncher with this version of RASM\n"); + FreeAssenv(ae); + exit(-5); + #endif + + if (ae->lz>=0 && ae->lzilz && ae->lzsection[ae->ilz-1].lzversion) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot start a new LZ section inside another one (%d)\n",ae->lz); + FreeAssenv(ae); + exit(-5); + } + curlz.version=1; + curlz.iw=ae->idx; + curlz.iorgzone=ae->io-1; + curlz.ibank=ae->activebank; + curlz.memstart=ae->outputadr; + curlz.memend=-1; + curlz.lzversion=18; + ae->lz=ae->ilz; + ObjectArrayAddDynamicValueConcat((void**)&ae->lzsection,&ae->ilz,&ae->mlz,&curlz,sizeof(curlz)); +} +void __LZSA2(struct s_assenv *ae) { + struct s_lz_section curlz={0}; + + if (!ae->wl[ae->idx].t) { + ae->idx++; + curlz.minmatch=atoi(ae->wl[ae->idx].w); + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LZSA2 directive may only have 1 parameter\n"); + } + } + #ifdef NO_3RD_PARTIES + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use 3rd parties cruncher with this version of RASM\n"); + FreeAssenv(ae); + exit(-5); + #endif + + if (ae->lz>=0 && ae->lzilz && ae->lzsection[ae->ilz-1].lzversion) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot start a new LZ section inside another one (%d)\n",ae->lz); + FreeAssenv(ae); + exit(-5); + } + curlz.version=2; + curlz.iw=ae->idx; + curlz.iorgzone=ae->io-1; + curlz.ibank=ae->activebank; + curlz.memstart=ae->outputadr; + curlz.memend=-1; + curlz.lzversion=18; + ae->lz=ae->ilz; + ObjectArrayAddDynamicValueConcat((void**)&ae->lzsection,&ae->ilz,&ae->mlz,&curlz,sizeof(curlz)); +} +void __LZAPU(struct s_assenv *ae) { + struct s_lz_section curlz; + + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LZ directive does not need any parameter\n"); + return; + } + #ifdef NO_3RD_PARTIES + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use 3rd parties cruncher with this version of RASM\n"); + FreeAssenv(ae); + exit(-5); + #endif + + if (ae->lz>=0 && ae->lzilz && ae->lzsection[ae->ilz-1].lzversion) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot start a new LZ section inside another one (%d)\n",ae->lz); + FreeAssenv(ae); + exit(-5); + } + curlz.iw=ae->idx; + curlz.iorgzone=ae->io-1; + curlz.ibank=ae->activebank; + curlz.memstart=ae->outputadr; + curlz.memend=-1; + curlz.lzversion=17; + ae->lz=ae->ilz; + ObjectArrayAddDynamicValueConcat((void**)&ae->lzsection,&ae->ilz,&ae->mlz,&curlz,sizeof(curlz)); +} +void __LZ4(struct s_assenv *ae) { + struct s_lz_section curlz; + + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LZ directive does not need any parameter\n"); + return; + } + #ifdef NO_3RD_PARTIES + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use 3rd parties cruncher with this version of RASM\n"); + FreeAssenv(ae); + exit(-5); + #endif + + if (ae->lz>=0 && ae->lzilz && ae->lzsection[ae->ilz-1].lzversion) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot start a new LZ section inside another one (%d)\n",ae->lz); + FreeAssenv(ae); + exit(-5); + } + curlz.iw=ae->idx; + curlz.iorgzone=ae->io-1; + curlz.ibank=ae->activebank; + curlz.memstart=ae->outputadr; + curlz.memend=-1; + curlz.lzversion=4; + ae->lz=ae->ilz; + ObjectArrayAddDynamicValueConcat((void**)&ae->lzsection,&ae->ilz,&ae->mlz,&curlz,sizeof(curlz)); +} +void __LZX0(struct s_assenv *ae) { + struct s_lz_section curlz; + + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LZ directive does not need any parameter\n"); + return; + } + #ifdef NO_3RD_PARTIES + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use 3rd parties cruncher with this version of RASM\n"); + FreeAssenv(ae); + exit(-5); + #endif + + if (ae->lz>=0 && ae->lzilz && ae->lzsection[ae->ilz-1].lzversion) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot start a new LZ section inside another one (%d)\n",ae->lz); + FreeAssenv(ae); + exit(-5); + } + curlz.version=MAX_OFFSET_ZX0; + curlz.iw=ae->idx; + curlz.iorgzone=ae->io-1; + curlz.ibank=ae->activebank; + curlz.memstart=ae->outputadr; + curlz.memend=-1; + curlz.lzversion=70; + ae->lz=ae->ilz; + ObjectArrayAddDynamicValueConcat((void**)&ae->lzsection,&ae->ilz,&ae->mlz,&curlz,sizeof(curlz)); +} +void __LZX0B(struct s_assenv *ae) { + struct s_lz_section curlz; + + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LZ directive does not need any parameter\n"); + return; + } + #ifdef NO_3RD_PARTIES + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use 3rd parties cruncher with this version of RASM\n"); + FreeAssenv(ae); + exit(-5); + #endif + + if (ae->lz>=0 && ae->lzilz && ae->lzsection[ae->ilz-1].lzversion) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot start a new LZ section inside another one (%d)\n",ae->lz); + FreeAssenv(ae); + exit(-5); + } + curlz.version=MAX_OFFSET_ZX0; + curlz.iw=ae->idx; + curlz.iorgzone=ae->io-1; + curlz.ibank=ae->activebank; + curlz.memstart=ae->outputadr; + curlz.memend=-1; + curlz.lzversion=71; + ae->lz=ae->ilz; + ObjectArrayAddDynamicValueConcat((void**)&ae->lzsection,&ae->ilz,&ae->mlz,&curlz,sizeof(curlz)); +} +void __LZX7(struct s_assenv *ae) { + struct s_lz_section curlz; + + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LZ directive does not need any parameter\n"); + return; + } + #ifdef NO_3RD_PARTIES + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use 3rd parties cruncher with this version of RASM\n"); + FreeAssenv(ae); + exit(-5); + #endif + + if (ae->lz>=0 && ae->lzilz && ae->lzsection[ae->ilz-1].lzversion) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot start a new LZ section inside another one (%d)\n",ae->lz); + FreeAssenv(ae); + exit(-5); + } + curlz.iw=ae->idx; + curlz.iorgzone=ae->io-1; + curlz.ibank=ae->activebank; + curlz.memstart=ae->outputadr; + curlz.memend=-1; + curlz.lzversion=7; + ae->lz=ae->ilz; + ObjectArrayAddDynamicValueConcat((void**)&ae->lzsection,&ae->ilz,&ae->mlz,&curlz,sizeof(curlz)); +} +void __LZEXO(struct s_assenv *ae) { + struct s_lz_section curlz; + + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LZ directive does not need any parameter\n"); + return; + } + #ifdef NO_3RD_PARTIES + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use 3rd parties cruncher with this version of RASM\n"); + FreeAssenv(ae); + exit(-5); + #endif + + if (ae->lz>=0 && ae->lzilz && ae->lzsection[ae->ilz-1].lzversion) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot start a new LZ section inside another one (%d)\n",ae->lz); + FreeAssenv(ae); + exit(-5); + } + curlz.iw=ae->idx; + curlz.iorgzone=ae->io-1; + curlz.ibank=ae->activebank; + curlz.memstart=ae->outputadr; + curlz.memend=-1; + curlz.lzversion=8; + ae->lz=ae->ilz; + ObjectArrayAddDynamicValueConcat((void**)&ae->lzsection,&ae->ilz,&ae->mlz,&curlz,sizeof(curlz)); +} +void __LZ48(struct s_assenv *ae) { + struct s_lz_section curlz; + + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LZ directive does not need any parameter\n"); + return; + } + if (ae->lz>=0 && ae->lzilz && ae->lzsection[ae->ilz-1].lzversion) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot start a new LZ section inside another one (%d)\n",ae->lz); + FreeAssenv(ae); + exit(-5); + } + curlz.iw=ae->idx; + curlz.iorgzone=ae->io-1; + curlz.ibank=ae->activebank; + curlz.memstart=ae->outputadr; + curlz.memend=-1; + curlz.lzversion=48; + ae->lz=ae->ilz; + ObjectArrayAddDynamicValueConcat((void**)&ae->lzsection,&ae->ilz,&ae->mlz,&curlz,sizeof(curlz)); +} +void __LZ49(struct s_assenv *ae) { + struct s_lz_section curlz; + + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LZ directive does not need any parameter\n"); + return; + } + if (ae->lz>=0 && ae->lzilz && ae->lzsection[ae->ilz-1].lzversion) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot start a new LZ section inside another one (%d)\n",ae->lz); + FreeAssenv(ae); + exit(-5); + } + + curlz.iw=ae->idx; + curlz.iorgzone=ae->io-1; + curlz.ibank=ae->activebank; + curlz.memstart=ae->outputadr; + curlz.memend=-1; + curlz.lzversion=49; + ae->lz=ae->ilz; + ObjectArrayAddDynamicValueConcat((void**)&ae->lzsection,&ae->ilz,&ae->mlz,&curlz,sizeof(curlz)); +} +void __LZCLOSE(struct s_assenv *ae) { + struct s_lz_section curlz; + + if (!ae->ilz || ae->lz==-1) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot close LZ section as it wasn't opened\n"); + return; + } + + ae->lzsection[ae->ilz-1].memend=ae->outputadr; + ae->lzsection[ae->ilz-1].ilabel=ae->il; + ae->lzsection[ae->ilz-1].iexpr=ae->ie; + // commentaire + curlz.iw=ae->idx; + curlz.iorgzone=ae->io-1; + curlz.ibank=ae->activebank; + curlz.memstart=ae->outputadr; + curlz.memend=-1; + curlz.lzversion=0; // intermediate zone + ae->lz=ae->ilz; + ObjectArrayAddDynamicValueConcat((void**)&ae->lzsection,&ae->ilz,&ae->mlz,&curlz,sizeof(curlz)); + + //ae->lz=-1; +} + +void __LIMIT(struct s_assenv *ae) { + if (ae->wl[ae->idx+1].t!=2) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + ___output_set_limit(ae,RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->outputadr,0,0)); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LIMIT directive need one integer parameter\n"); + } +} +void OverWriteCheck(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "OverWriteCheck" + + int i,j; + + /* overwrite checking */ + i=ae->io-1; { + if (ae->orgzone[i].memstart!=ae->orgzone[i].memend) { + for (j=0;jio-1;j++) { + if (ae->orgzone[j].memstart!=ae->orgzone[j].memend && !ae->orgzone[j].nocode) { + if (ae->orgzone[i].ibank==ae->orgzone[j].ibank) { + if ((ae->orgzone[i].memstart>=ae->orgzone[j].memstart && ae->orgzone[i].memstartorgzone[j].memend) + || (ae->orgzone[i].memend>ae->orgzone[j].memstart && ae->orgzone[i].memendorgzone[j].memend) + || (ae->orgzone[i].memstart<=ae->orgzone[j].memstart && ae->orgzone[i].memend>=ae->orgzone[j].memend)) { + ae->idx--; + if (ae->orgzone[j].protect) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"PROTECTED section error [%s] L%d [#%04X-#%04X-B%d] with [%s] L%d [#%04X/#%04X]\n",ae->filename[ae->orgzone[j].ifile],ae->orgzone[j].iline,ae->orgzone[j].memstart,ae->orgzone[j].memend,ae->orgzone[j].ibank<32?ae->orgzone[j].ibank:0,ae->filename[ae->orgzone[i].ifile],ae->orgzone[i].iline,ae->orgzone[i].memstart,ae->orgzone[i].memend); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Assembling overwrite [%s] L%d [#%04X-#%04X-B%d] with [%s] L%d [#%04X/#%04X]\n",ae->filename[ae->orgzone[j].ifile],ae->orgzone[j].iline,ae->orgzone[j].memstart,ae->orgzone[j].memend,ae->orgzone[j].ibank<32?ae->orgzone[j].ibank:0,ae->filename[ae->orgzone[i].ifile],ae->orgzone[i].iline,ae->orgzone[i].memstart,ae->orgzone[i].memend); + } + i=j=ae->io; + break; + } + } + } + } + } + } +} + +void ___new_memory_space(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "___new_memory_space" + + unsigned char *mem; + struct s_orgzone orgzone={0}; + + __internal_UpdateLZBlockIfAny(ae); + if (ae->io) { + ae->orgzone[ae->io-1].memend=ae->outputadr; + } + if (ae->lz>=0) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: LZ section wasn't closed before a new memory space directive\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + if (ae->erronwarn) MaxError(ae); + } + __LZCLOSE(ae); + } + ae->activebank=ae->nbbank; + mem=MemMalloc(65536); + memset(mem,0,65536); + ObjectArrayAddDynamicValueConcat((void**)&ae->mem,&ae->nbbank,&ae->maxbank,&mem,sizeof(mem)); + + ae->outputadr=0; + ae->codeadr=0; + orgzone.memstart=0; + orgzone.ibank=ae->activebank; + orgzone.nocode=ae->nocode=0; + orgzone.inplace=1; + ObjectArrayAddDynamicValueConcat((void**)&ae->orgzone,&ae->io,&ae->mo,&orgzone,sizeof(orgzone)); + + OverWriteCheck(ae); +} + +void __BANK(struct s_assenv *ae) { + struct s_orgzone orgzone={0}; + int oldcode=0,oldoutput=0; + int i; + __internal_UpdateLZBlockIfAny(ae); + + if (ae->io) { + ae->orgzone[ae->io-1].memend=ae->outputadr; + } + /* without parameter, create a new empty space */ + if (ae->wl[ae->idx].t==1) { + ___new_memory_space(ae); + return; + } + + ae->bankmode=1; + /* using BANK without build mode will select cartridge output as default */ + if (!ae->forceROM && !ae->forcecpr && !ae->forcesnapshot && !ae->forcezx) ae->forcecpr=1; + + if (ae->wl[ae->idx+1].t!=2) { + if (strcmp(ae->wl[ae->idx+1].w,"NEXT")==0) { + /* are we in a temporary space or in the very last bank? */ + if (ae->activebank>=260-1) { + ___new_memory_space(ae); + return; + } + /* switch to next bank! */ + ae->activebank++; + } else { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + ae->activebank=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); + } + if (ae->forcecpr && (ae->activebank<0 || ae->activebank>31) && !ae->extendedCPR) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"FATAL - Bank selection must be from 0 to 31 in cartridge mode\n"); + FreeAssenv(ae); + exit(2); + } else if (ae->extendedCPR && (ae->activebank<0 || ae->activebank>256) && !ae->extendedCPR) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"FATAL - Bank selection must be from 0 to 256 in extended cartridge mode\n"); + FreeAssenv(ae); + exit(2); + } else if (ae->forcezx && (ae->activebank<0 || ae->activebank>7)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"FATAL - Bank selection must be from 0 to 7 in ZX Spectrum mode\n"); + FreeAssenv(ae); + exit(2); + } else if (ae->forceROM && (ae->activebank<0 || ae->activebank>=256)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"FATAL - Bank selection must be from 0 to 255 in ROM mode\n"); + FreeAssenv(ae); + exit(2); + } else if (ae->forcesnapshot && (ae->activebank<0 || ae->activebank>=260)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"FATAL - Bank selection must be from 0 to 259 in snapshot mode\n"); + FreeAssenv(ae); + exit(2); + } + /* bankset control */ + if (ae->forcesnapshot && ae->bankset[ae->activebank/4]) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot BANK %d was already select by a previous BANKSET %d\n",ae->activebank,(int)ae->activebank/4); + ae->idx++; + return; + } else { + ae->bankused[ae->activebank]=1; + } + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BANK directive need one integer parameter\n"); + return; + } + if (ae->lz>=0) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: LZ section wasn't closed before a new BANK directive\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + if (ae->erronwarn) MaxError(ae); + } + __LZCLOSE(ae); + } + + /* try to get an old ORG settings backward */ + for (i=ae->io-1;i>=0;i--) { + if (ae->orgzone[i].ibank==ae->activebank) { + oldcode=ae->orgzone[i].memend; + oldoutput=ae->orgzone[i].memend; + break; + } + } + ae->outputadr=oldoutput; + ae->codeadr=oldcode; + orgzone.memstart=ae->outputadr; + /* legacy */ + orgzone.ibank=ae->activebank; + orgzone.nocode=ae->nocode=0; + ObjectArrayAddDynamicValueConcat((void**)&ae->orgzone,&ae->io,&ae->mo,&orgzone,sizeof(orgzone)); + + OverWriteCheck(ae); +} + +void __BANKSET(struct s_assenv *ae) { + struct s_orgzone orgzone={0}; + int ibank,i; + + __internal_UpdateLZBlockIfAny(ae); + + if (!ae->forcesnapshot && !ae->forcecpr && !ae->forcezx && !ae->forceROM) ae->forcesnapshot=1; + if (!ae->forcesnapshot) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BANKSET directive is specific to snapshot output\n"); + return; + } + + if (ae->io) { + ae->orgzone[ae->io-1].memend=ae->outputadr; + } + ae->bankmode=1; + + if (ae->wl[ae->idx+1].t!=2) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + ae->activebank=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); + ae->activebank*=4; + if (ae->forcesnapshot && (ae->activebank<0 || ae->activebank>=260)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"FATAL - Bank set selection must be from 0 to 64 in snapshot mode\n"); + FreeAssenv(ae); + exit(2); + } + /* control */ + ibank=ae->activebank; + if (!ae->bankset[ibank>>2]) { + if (ae->bankused[ibank] || ae->bankused[ibank+1]|| ae->bankused[ibank+2]|| ae->bankused[ibank+3]) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot BANKSET because bank %d was already selected in single page mode\n",ibank); + ae->idx++; + return; + } else { + /* in case of EMURAM, rebuild bankset with existing data (this is done only once) */ + ae->bankset[ibank>>2]=1; + for (i=16384;i<32768;i++) { + ae->mem[ibank][i]=ae->mem[ibank+1][i]; + ae->mem[ibank][i+16384]=ae->mem[ibank+2][i+16384]; + ae->mem[ibank][i+32768]=ae->mem[ibank+3][i+32768]; + } + } + } + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BANKSET directive need one integer parameter\n"); + return; + } + if (ae->lz>=0) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: LZ section wasn't closed before a new BANKSET directive\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + if (ae->erronwarn) MaxError(ae); + } + __LZCLOSE(ae); + } + + ae->outputadr=0; + ae->codeadr=0; + orgzone.memstart=0; + orgzone.ibank=ae->activebank; + orgzone.nocode=ae->nocode=0; + ObjectArrayAddDynamicValueConcat((void**)&ae->orgzone,&ae->io,&ae->mo,&orgzone,sizeof(orgzone)); + + OverWriteCheck(ae); +} + + +void __NameBANK(struct s_assenv *ae) { + int ibank; + + ae->bankmode=1; + if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + if (!StringIsQuote(ae->wl[ae->idx+2].w)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Syntax is NAMEBANK ,''\n"); + } else { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + ibank=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); + if (ibank<0 || ibank>=BANK_MAX_NUMBER) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"NAMEBANK selection must be from 0 to %d\n",BANK_MAX_NUMBER); + } else { + ae->iwnamebank[ibank]=ae->idx+2; + } + } + ae->idx+=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"NAMEBANK directive need one integer parameter and a string\n"); + } +} + +/*** + Winape little compatibility for CPR writing! +*/ +void __WRITE(struct s_assenv *ae) { + int ok=0; + int lower=-1,upper=-1,bank=-1; + + if (!ae->wl[ae->idx].t && strcmp(ae->wl[ae->idx+1].w,"DIRECT")==0 && !ae->wl[ae->idx+1].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+2].w,0); + lower=RoundComputeExpression(ae,ae->wl[ae->idx+2].w,ae->codeadr,0,0); + if (!ae->wl[ae->idx+2].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+3].w,0); + upper=RoundComputeExpression(ae,ae->wl[ae->idx+3].w,ae->codeadr,0,0); + } + if (!ae->wl[ae->idx+3].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+4].w,0); + bank=RoundComputeExpression(ae,ae->wl[ae->idx+4].w,ae->codeadr,0,0); + } + + if (ae->maxam) { + if (lower==65535) lower=-1; + if (upper==65535) upper=-1; + if (bank==65535) bank=-1; + } + + if (lower!=-1) { + if (lower>=0 && lower<8) { + ae->idx+=1; + __BANK(ae); + ok=1; + } else { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: WRITE DIRECT lower ROM ignored (value %d out of bounds 0-7)\n",GetCurrentFile(ae),ae->wl[ae->idx].l,lower); + if (ae->erronwarn) MaxError(ae); + } + } + } else if (upper!=-1) { + if (upper>=0 && ((ae->forcecpr && upper<32) || (ae->forcesnapshot && upperidx+=2; + __BANK(ae); + ok=1; + } else { + if (!ae->forcecpr && !ae->forcesnapshot) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: WRITE DIRECT select a ROM without cartridge output\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + if (ae->erronwarn) MaxError(ae); + } + } else { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: WRITE DIRECT upper ROM ignored (value %d out of bounds 0-31)\n",GetCurrentFile(ae),ae->wl[ae->idx].l,upper); + if (ae->erronwarn) MaxError(ae); + } + } + } + } else if (bank!=-1) { + /* selection de bank on ouvre un nouvel espace */ + } else { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: meaningless WRITE DIRECT\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + if (ae->erronwarn) MaxError(ae); + } + } + } + while (!ae->wl[ae->idx].t) ae->idx++; + if (!ok) { + ___new_memory_space(ae); + } +} +void __CHARSET(struct s_assenv *ae) { + int i,s,e,v,tquote; + + if (ae->wl[ae->idx].t==1) { + /* reinit charset */ + for (i=0;i<256;i++) + ae->charset[i]=i; + } else if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + /* string,value | byte,value */ + ExpressionFastTranslate(ae,&ae->wl[ae->idx+2].w,0); + v=RoundComputeExpression(ae,ae->wl[ae->idx+2].w,ae->codeadr,0,0); + if (ae->wl[ae->idx+1].w[0]=='\'' || ae->wl[ae->idx+1].w[0]=='"') { + tquote=ae->wl[ae->idx+1].w[0]; + if (ae->wl[ae->idx+1].w[strlen(ae->wl[ae->idx+1].w)-1]==tquote) { + i=1; + while (ae->wl[ae->idx+1].w[i] && ae->wl[ae->idx+1].w[i]!=tquote) { + if (ae->wl[ae->idx+1].w[i]=='\\') i++; + ae->charset[(unsigned int)ae->wl[ae->idx+1].w[i]&0xFF]=(unsigned char)v++; + i++; + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CHARSET string,value has invalid quote!\n"); + } + } else { + i=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); + if (i>=0 && i<256) { + ae->charset[i]=(unsigned char)v; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CHARSET byte value must be 0-255\n"); + } + } + ae->idx+=2; + } else if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && !ae->wl[ae->idx+2].t && ae->wl[ae->idx+3].t==1) { + /* start,end,value */ + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + ExpressionFastTranslate(ae,&ae->wl[ae->idx+2].w,0); + ExpressionFastTranslate(ae,&ae->wl[ae->idx+3].w,0); + s=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); + e=RoundComputeExpression(ae,ae->wl[ae->idx+2].w,ae->codeadr,0,0); + v=RoundComputeExpression(ae,ae->wl[ae->idx+3].w,ae->codeadr,0,0); + ae->idx+=3; + if (s<=e && s>=0 && e<256) { + for (i=s;i<=e;i++) { + ae->charset[i]=(unsigned char)v++; + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CHARSET Winape directive wrong interval value\n"); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CHARSET Winape directive wrong parameter count\n"); + } +} + +void PushGlobal(struct s_assenv *ae) { + char *zelast; + if (ae->lastgloballabel) zelast=TxtStrDup(ae->lastgloballabel); else zelast=NULL; + ObjectArrayAddDynamicValueConcat((void **)&ae->globalstack,&ae->igs,&ae->mgs,&zelast,sizeof(char *)); + +#if TRACE_LABEL +printf("==> PushGlobal on Stack [%s] igs=%d\n",zelast,ae->igs); +#endif +} + +void PopGlobal(struct s_assenv *ae) { + if (ae->igs) { + ae->igs--; +#if TRACE_LABEL +printf("<== PopGlobal on Stack [%s] igs=%d\n",ae->globalstack[ae->igs],ae->igs+1); +#endif + if (ae->lastglobalalloc) MemFree(ae->lastgloballabel); + + if (ae->globalstack[ae->igs]) { + ae->lastgloballabel=TxtStrDup(ae->globalstack[ae->igs]); + ae->lastgloballabellen=strlen(ae->lastgloballabel); + ae->lastglobalalloc=1; + } else { + ae->lastgloballabel=NULL; + ae->lastgloballabellen=0; + ae->lastglobalalloc=0; + } + + if (ae->globalstack[ae->igs]) MemFree(ae->globalstack[ae->igs]); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"PopGlobal INTERNAL ERROR / Please report\n"); + } +} + + +void __MACRO(struct s_assenv *ae) { + struct s_macro curmacro={0}; + char *referentfilename,*zeparam; + int refidx,idx,getparam=1; + struct s_wordlist curwl; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t!=2) { + /* get the name */ + curmacro.mnemo=ae->wl[ae->idx+1].w; + curmacro.crc=GetCRC(curmacro.mnemo); + if (ae->wl[ae->idx+1].t) { + getparam=0; + } + /* overload forbidden */ + /* macro, keywords and directives forbidden */ + if (SearchMacro(ae,curmacro.crc,curmacro.mnemo)>=0) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Macro already defined with this name\n"); + } else { + if ((SearchDico(ae,ae->wl[ae->idx+1].w,curmacro.crc))!=NULL) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Macro definition: There is already a variable with this name\n"); + } else { + if ((SearchLabel(ae,ae->wl[ae->idx+1].w,curmacro.crc))!=NULL) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Macro definition: There is already a label with this name\n"); + } else { + if ((SearchAlias(ae,curmacro.crc,ae->wl[ae->idx+1].w))!=-1) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Macro definition: There is already an alias with this name\n"); + } else { + if (IsRegister(curmacro.mnemo)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Macro definition: Cannot choose a register as macro name\n"); + } + } + } + } + } + + idx=ae->idx+2; + while (ae->wl[idx].t!=2 && (GetCRC(ae->wl[idx].w)!=CRC_MEND || strcmp(ae->wl[idx].w,"MEND")!=0) && (GetCRC(ae->wl[idx].w)!=CRC_ENDM || strcmp(ae->wl[idx].w,"ENDM")!=0)) { + if (GetCRC(ae->wl[idx].w)==CRC_MACRO || strcmp(ae->wl[idx].w,"MACRO")==0) { + /* inception interdite */ + referentfilename=GetCurrentFile(ae); + refidx=ae->idx; + ae->idx=idx; + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"You cannot define a macro inside another one (MACRO %s in [%s] L%d)\n",ae->wl[refidx+1].w,referentfilename,ae->wl[refidx].l); + __STOP(ae); + } + if (getparam) { + /* on prepare les parametres au remplacement */ + zeparam=MemMalloc(strlen(ae->wl[idx].w)+3); + if (ae->as80) { + sprintf(zeparam,"%s",ae->wl[idx].w); + } else { + sprintf(zeparam,"{%s}",ae->wl[idx].w); + } + curmacro.nbparam++; + curmacro.param=MemRealloc(curmacro.param,curmacro.nbparam*sizeof(char **)); + curmacro.param[curmacro.nbparam-1]=zeparam; + if (ae->wl[idx].t) { + /* duplicate parameters without brackets MUST be an OPTION */ + getparam=0; + } + } else { + /* copie la liste de mots */ + curwl=ae->wl[idx]; + ObjectArrayAddDynamicValueConcat((void **)&curmacro.wc,&curmacro.nbword,&curmacro.maxword,&curwl,sizeof(struct s_wordlist)); + } + idx++; + } + if (ae->wl[idx].t==2) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Macro was not closed\n"); + } + ObjectArrayAddDynamicValueConcat((void**)&ae->macro,&ae->imacro,&ae->mmacro,&curmacro,sizeof(curmacro)); + /* le quicksort n'est pas optimal mais on n'est pas supposé en créer des milliers */ + qsort(ae->macro,ae->imacro,sizeof(struct s_macro),cmpmacros); + + /* ajustement des mots lus */ + if (ae->wl[idx].t==2) idx--; + ae->idx=idx; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"MACRO definition need at least one parameter for the name of the macro\n"); + } +} + +struct s_wordlist *__MACRO_EXECUTE(struct s_assenv *ae, int imacro) { + struct s_wordlist *cpybackup; + int nbparam=0,idx,i,j,idad; + int ifile,iline,iu,lenparam; + double v; + struct s_macro_position curmacropos={0}; + char *zeparam=NULL,*txtparamlist; + int reload=0; + + idx=ae->idx; + while (!ae->wl[idx].t) { + nbparam++; + idx++; + } + + /* hack to secure macro without parameters with void argument */ + if (!ae->macro[imacro].nbparam) { + if (nbparam) { + if (nbparam==1 && strcmp(ae->wl[ae->idx+1].w,"(VOID)")==0) { + nbparam=0; + reload=1; + } + } else { + if (ae->macrovoid) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"MACRO [%s] used without (void) and option -void used!\n",ae->macro[imacro].mnemo); + } + } + } + /* macro must avoid extra params! */ + + /* cannot VOID a macro with parameters! */ + if (ae->macro[imacro].nbparam && strcmp(ae->wl[ae->idx+1].w,"(VOID)")==0) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"MACRO [%s] has %d parameter%s\n",ae->macro[imacro].mnemo,ae->macro[imacro].nbparam,ae->macro[imacro].nbparam>1?"s":""); + while (!ae->wl[ae->idx].t) { + ae->idx++; + } + ae->idx++; + } else { + if (nbparam!=ae->macro[imacro].nbparam) { + lenparam=1; // macro without parameters! + for (i=0;imacro[imacro].nbparam;i++) { + lenparam+=strlen(ae->macro[imacro].param[i])+3; + } + txtparamlist=MemMalloc(lenparam); + txtparamlist[0]=0; + for (i=0;imacro[imacro].nbparam;i++) { + strcat(txtparamlist,ae->macro[imacro].param[i]); + strcat(txtparamlist," "); + } + + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"MACRO [%s] was defined with %d parameter%s %s\n",ae->macro[imacro].mnemo,ae->macro[imacro].nbparam,ae->macro[imacro].nbparam>1?"s":"",txtparamlist); + while (!ae->wl[ae->idx].t) { + ae->idx++; + } + ae->idx++; + } else { + /* free macro call as we will overwrite it */ + MemFree(ae->wl[ae->idx].w); + /* is there a void to free? */ + if (reload) { + MemFree(ae->wl[ae->idx+1].w); + } + /* eval parameters? */ + for (i=0;iwl[ae->idx+1+i].w,"{EVAL}",6)==0) { + /* parametre entre chevrons, il faut l'interpreter d'abord */ + zeparam=TxtStrDup(ae->wl[ae->idx+1+i].w+6); + ExpressionFastTranslate(ae,&zeparam,1); + v=ComputeExpressionCore(ae,zeparam,ae->codeadr,0); + MemFree(zeparam); + zeparam=MemMalloc(32); + snprintf(zeparam,31,"%lf",v); + zeparam[31]=0; + MemFree(ae->wl[ae->idx+1+i].w); + ae->wl[ae->idx+1+i].w=zeparam; + } + } + /* backup parameters */ + cpybackup=MemMalloc((nbparam+1)*sizeof(struct s_wordlist)); + for (i=0;iwl[ae->idx+1+i]; + } + /************************ + insert macro position + *************************/ + curmacropos.start=ae->idx; + curmacropos.end=ae->idx+ae->macro[imacro].nbword; + curmacropos.value=ae->macrocounter; + /* which level? */ + curmacropos.pushed=0; + if (!ae->imacropos) { + curmacropos.level=1; + } else { + if (ae->macropos[ae->imacropos-1].end<=curmacropos.start) { + /* same level */ + curmacropos.level=ae->macropos[ae->imacropos-1].level; + } else { + /* inception */ + curmacropos.level=ae->macropos[ae->imacropos-1].level+1; + } + } + + ObjectArrayAddDynamicValueConcat((void**)&ae->macropos,&ae->imacropos,&ae->mmacropos,&curmacropos,sizeof(curmacropos)); + + /* are we in a repeat/while block? */ + for (iu=0;iuir;iu++) if (ae->repeat[iu].maximimacropos) ae->repeat[iu].maxim=ae->imacropos; + for (iu=0;iuiw;iu++) if (ae->whilewend[iu].maximimacropos) ae->whilewend[iu].maxim=ae->imacropos; + + /* update daddy macropos */ + for (idad=0;idadimacropos-1;idad++) { + if (ae->macropos[idad].end>curmacropos.start) { + ae->macropos[idad].end+=ae->macro[imacro].nbword-1-nbparam-reload; /* coz la macro compte un mot! */ + } + } + + #if 0 + for (idad=0;idadimacropos;idad++) { + printf("macropos[%d]=%d -> %d\n",idad,ae->macropos[idad].start,ae->macropos[idad].end); + } + #endif + /* insert at macro position and replace macro+parameters */ + if (ae->macro[imacro].nbword>1+nbparam+reload) { + ae->nbword+=ae->macro[imacro].nbword-1-nbparam-reload; + ae->wl=MemRealloc(ae->wl,ae->nbword*sizeof(struct s_wordlist)); + } else { + /* si on réduit pas de realloc pour ne pas perdre de donnees */ + ae->nbword+=ae->macro[imacro].nbword-1-nbparam-reload; + } + iline=ae->wl[ae->idx].l; + ifile=ae->wl[ae->idx].ifile; + MemMove(&ae->wl[ae->idx+ae->macro[imacro].nbword],&ae->wl[ae->idx+reload+nbparam+1],(ae->nbword-ae->idx-ae->macro[imacro].nbword)*sizeof(struct s_wordlist)); + + for (i=0;imacro[imacro].nbword;i++) { + ae->wl[i+ae->idx].w=TxtStrDup(ae->macro[imacro].wc[i].w); + ae->wl[i+ae->idx].l=iline; + ae->wl[i+ae->idx].ifile=ifile; + /* @@@sujet a evolution, ou double controle */ + ae->wl[i+ae->idx].t=ae->macro[imacro].wc[i].t; + ae->wl[i+ae->idx].e=ae->macro[imacro].wc[i].e; + } + /* replace */ + idx=ae->idx; + for (i=0;imacro[imacro].nbword;j++) { + /* tags in upper case for replacement in quotes */ + if (StringIsQuote(ae->wl[j].w)) { + int lm,touched; + for (lm=touched=0;ae->wl[j].w[lm];lm++) { + if (ae->wl[j].w[lm]=='{') touched++; else if (ae->wl[j].w[lm]=='}') touched--; else if (touched) ae->wl[j].w[lm]=toupper(ae->wl[j].w[lm]); + } + } +//printf("MACRO_EXECUTE word[%d]=[%s] param[%d]=[%s] cpybackup[%d]=[%s]\n",j,ae->wl[j].w,i,ae->macro[imacro].param[i],i,cpybackup[i].w); + ae->wl[j].w=TxtReplace(ae->wl[j].w,ae->macro[imacro].param[i],cpybackup[i].w,0); + } + MemFree(cpybackup[i].w); + } + MemFree(cpybackup); + + /* look for specific tags */ + for (j=idx;jmacro[imacro].nbword;j++) { + switch (GetCRC(ae->wl[j].w)) { + case CRC_AF_HIGH:if (strcmp(ae->wl[j].w,"AF.HIGH")==0) strcpy(ae->wl[j].w,"A");break; + case CRC_AF_LOW: if (strcmp(ae->wl[j].w,"AF.LOW")==0) strcpy(ae->wl[j].w,"F");break; + case CRC_BC_HIGH:if (strcmp(ae->wl[j].w,"BC.HIGH")==0) strcpy(ae->wl[j].w,"B");break; + case CRC_BC_LOW: if (strcmp(ae->wl[j].w,"BC.LOW")==0) strcpy(ae->wl[j].w,"C");break; + case CRC_DE_HIGH:if (strcmp(ae->wl[j].w,"DE.HIGH")==0) strcpy(ae->wl[j].w,"D");break; + case CRC_DE_LOW: if (strcmp(ae->wl[j].w,"DE.LOW")==0) strcpy(ae->wl[j].w,"E");break; + case CRC_HL_HIGH:if (strcmp(ae->wl[j].w,"HL.HIGH")==0) strcpy(ae->wl[j].w,"H");break; + case CRC_HL_LOW: if (strcmp(ae->wl[j].w,"HL.LOW")==0) strcpy(ae->wl[j].w,"L");break; + case CRC_IX_HIGH:if (strcmp(ae->wl[j].w,"IX.HIGH")==0) strcpy(ae->wl[j].w,"XH");break; + case CRC_IX_LOW: if (strcmp(ae->wl[j].w,"IX.LOW")==0) strcpy(ae->wl[j].w,"XL");break; + case CRC_IY_HIGH:if (strcmp(ae->wl[j].w,"IY.HIGH")==0) strcpy(ae->wl[j].w,"YH");break; + case CRC_IY_LOW: if (strcmp(ae->wl[j].w,"IY.LOW")==0) strcpy(ae->wl[j].w,"YL");break; + default:break; + } + } + + /* macro replaced, need to rollback index */ + //ae->idx--; + } + } + /* a chaque appel de macro on incremente le compteur pour les labels locaux */ + ae->macrocounter++; + + return ae->wl; +} + +/* + ticker start, + ticker stop, +*/ +void __TICKER(struct s_assenv *ae) { + struct s_expr_dico *tvar; + struct s_ticker ticker; + int crc,i; + + if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + crc=GetCRC(ae->wl[ae->idx+2].w); + + if (strcmp(ae->wl[ae->idx+1].w,"START")==0) { + /* is there already a counter? */ + for (i=0;iiticker;i++) { + if (ae->ticker[i].crc==crc && strcmp(ae->wl[ae->idx+2].w,ae->ticker[i].varname)==0) { + break; + } + } + if (i==ae->iticker) { + ticker.varname=TxtStrDup(ae->wl[ae->idx+2].w); + ticker.crc=crc; + ObjectArrayAddDynamicValueConcat((void **)&ae->ticker,&ae->iticker,&ae->mticker,&ticker,sizeof(struct s_ticker)); + } + ae->ticker[i].nopstart=ae->nop; + ae->ticker[i].tickerstart=ae->tick; + } else if (strncmp(ae->wl[ae->idx+1].w,"STOP",4)==0) { + for (i=0;iiticker;i++) { + if (ae->ticker[i].crc==crc && strcmp(ae->wl[ae->idx+2].w,ae->ticker[i].varname)==0) { + break; + } + } + if (iiticker) { + /* set var */ + if ((tvar=SearchDico(ae,ae->wl[ae->idx+2].w,crc))!=NULL) { + /* compute nop count */ + if (ae->wl[ae->idx+1].w[4]=='Z') tvar->v=ae->tick-ae->ticker[i].tickerstart; + else tvar->v=ae->nop-ae->ticker[i].nopstart; + } else { + /* create var with nop count */ + if (ae->wl[ae->idx+1].w[4]=='Z') ExpressionSetDicoVar(ae,ae->wl[ae->idx+2].w,ae->tick-ae->ticker[i].tickerstart,0); + else ExpressionSetDicoVar(ae,ae->wl[ae->idx+2].w,ae->nop-ae->ticker[i].nopstart,0); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"TICKER not found\n"); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"usage is TICKER start/stop(z),\n"); + } + ae->idx+=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"usage is TICKER start/stop(z),\n"); + } +} + +void __LET(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ae->idx++; + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + RoundComputeExpression(ae,ae->wl[ae->idx].w,ae->codeadr,0,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LET useless Winape directive need one expression\n"); + } +} + +void __RUN(struct s_assenv *ae) { + int ramconf=0xC0; + + if (!ae->wl[ae->idx].t) { + ae->current_run_idx=ae->idx+1; + if (ae->forcezx) { + PushExpression(ae,ae->idx+1,E_EXPRESSION_ZXRUN); // delayed RUN value + ae->idx++; + if (!ae->wl[ae->idx].t) { + PushExpression(ae,ae->idx+1,E_EXPRESSION_ZXSTACK); // delayed STACK value + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"usage is RUN
, (ZX mode, you must set address+stack)\n"); + } + } else { + PushExpression(ae,ae->idx+1,E_EXPRESSION_RUN); // delayed RUN value + ae->idx++; + if (!ae->wl[ae->idx].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + ramconf=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); + ae->idx++; + if (ramconf<0xC0 || ramconf>0xFF) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: ram configuration out of bound %X forced to #C0\n",GetCurrentFile(ae),ae->wl[ae->idx].l,ramconf); + if (ae->erronwarn) MaxError(ae); + } + ramconf=0xC0; + } + ae->snapshot.ramconfiguration=ramconf; + } + } + } else { + if (ae->forcezx) MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"usage is RUN
, (ZX mode)\n"); + else MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"usage is RUN
[,]\n"); + } + if (ae->rundefined && !ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: run address redefinition\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + if (ae->erronwarn) MaxError(ae); + } + ae->rundefined=1; +} +void __BREAKPOINT(struct s_assenv *ae) { + struct s_breakpoint breakpoint={0}; + + if (ae->activebank>3) breakpoint.bank=1; + if (ae->wl[ae->idx].t) { + breakpoint.address=ae->codeadr; + ObjectArrayAddDynamicValueConcat((void **)&ae->breakpoint,&ae->ibreakpoint,&ae->maxbreakpoint,&breakpoint,sizeof(struct s_breakpoint)); + } else if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + breakpoint.address=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); + ObjectArrayAddDynamicValueConcat((void **)&ae->breakpoint,&ae->ibreakpoint,&ae->maxbreakpoint,&breakpoint,sizeof(struct s_breakpoint)); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is BREAKPOINT [address]\n"); + } +} + +void __SNASET(struct s_assenv *ae) { + int myvalue,idx; + + if (!ae->forcecpr && !ae->forcetape && !ae->forcezx && !ae->forceROM) { + ae->forcesnapshot=1; + } else { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: Cannot SNASET when already in ZX/ROM/cartridge/tape output\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + if (ae->erronwarn) MaxError(ae); + } + } + + if (!ae->wl[ae->idx].t) { + ae->idx++; + /* TWO parameters */ + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + /* parameter value */ + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + myvalue=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); + + /* Z80 register/value */ + if (strcmp(ae->wl[ae->idx].w,"Z80_AF")==0) { + ae->snapshot.registers.general.F=myvalue&0xFF; + ae->snapshot.registers.general.A=(myvalue>>8)&0xFF; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_F")==0) { + ae->snapshot.registers.general.F=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_A")==0) { + ae->snapshot.registers.general.A=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_BC")==0) { + ae->snapshot.registers.general.C=myvalue&0xFF; + ae->snapshot.registers.general.B=(myvalue>>8)&0xFF; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_C")==0) { + ae->snapshot.registers.general.C=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_B")==0) { + ae->snapshot.registers.general.B=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_DE")==0) { + ae->snapshot.registers.general.E=myvalue&0xFF; + ae->snapshot.registers.general.D=(myvalue>>8)&0xFF; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_E")==0) { + ae->snapshot.registers.general.E=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_D")==0) { + ae->snapshot.registers.general.D=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_HL")==0) { + ae->snapshot.registers.general.L=myvalue&0xFF; + ae->snapshot.registers.general.H=(myvalue>>8)&0xFF; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_L")==0) { + ae->snapshot.registers.general.L=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_H")==0) { + ae->snapshot.registers.general.H=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_I")==0) { + ae->snapshot.registers.regI=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_R")==0) { + ae->snapshot.registers.R=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_IFF0")==0) { + ae->snapshot.registers.IFF0=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_IFF1")==0) { + ae->snapshot.registers.IFF1=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_IX")==0) { + ae->snapshot.registers.LX=myvalue&0xFF; + ae->snapshot.registers.HX=(myvalue>>8)&0xFF; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_IXL")==0) { + ae->snapshot.registers.LX=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_IXH")==0) { + ae->snapshot.registers.HX=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_IY")==0) { + ae->snapshot.registers.LY=myvalue&0xFF; + ae->snapshot.registers.HY=(myvalue>>8)&0xFF; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_IYL")==0) { + ae->snapshot.registers.LY=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_IYH")==0) { + ae->snapshot.registers.HY=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_SP")==0) { + ae->snapshot.registers.LSP=myvalue&0xFF; + ae->snapshot.registers.HSP=(myvalue>>8)&0xFF; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_PC")==0) { + ae->snapshot.registers.LPC=myvalue&0xFF; + ae->snapshot.registers.HPC=(myvalue>>8)&0xFF; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_IM")==0) { + ae->snapshot.registers.IM=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_AFX")==0) { + ae->snapshot.registers.alternate.F=myvalue&0xFF; + ae->snapshot.registers.alternate.A=(myvalue>>8)&0xFF; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_AX")==0) { + ae->snapshot.registers.alternate.A=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_FX")==0) { + ae->snapshot.registers.alternate.F=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_BCX")==0) { + ae->snapshot.registers.alternate.C=myvalue&0xFF; + ae->snapshot.registers.alternate.B=(myvalue>>8)&0xFF; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_CX")==0) { + ae->snapshot.registers.alternate.C=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_BX")==0) { + ae->snapshot.registers.alternate.B=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_DEX")==0) { + ae->snapshot.registers.alternate.E=myvalue&0xFF; + ae->snapshot.registers.alternate.D=(myvalue>>8)&0xFF; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_EX")==0) { + ae->snapshot.registers.alternate.E=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_DX")==0) { + ae->snapshot.registers.alternate.D=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_HLX")==0) { + ae->snapshot.registers.alternate.L=myvalue&0xFF; + ae->snapshot.registers.alternate.H=(myvalue>>8)&0xFF; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_LX")==0) { + ae->snapshot.registers.alternate.L=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"Z80_HX")==0) { + ae->snapshot.registers.alternate.H=myvalue; + /* Gate Array / CRTC / PPI / FDD */ + } else if (strcmp(ae->wl[ae->idx].w,"GA_PEN")==0) { + ae->snapshot.gatearray.selectedpen=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"GA_ROMCFG")==0) { + ae->snapshot.gatearray.multiconfiguration=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"GA_RAMCFG")==0) { + ae->snapshot.ramconfiguration=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"CRTC_SEL")==0) { + ae->snapshot.crtc.selectedregister=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"ROM_UP")==0) { + ae->snapshot.romselect=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"PPI_A")==0) { + ae->snapshot.ppi.portA=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"PPI_B")==0) { + ae->snapshot.ppi.portB=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"PPI_C")==0) { + ae->snapshot.ppi.portC=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"PPI_CTL")==0) { + ae->snapshot.ppi.control=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"PSG_SEL")==0) { + ae->snapshot.psg.selectedregister=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"CPC_TYPE")==0) { + ae->snapshot.CPCType=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"INT_NUM")==0) { + ae->snapshot.interruptnumber=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"FDD_MOTOR")==0) { + ae->snapshot.fdd.motorstate=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"FDD_TRACK")==0) { + ae->snapshot.fdd.physicaltrack=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"PRNT_DATA")==0) { + ae->snapshot.printerstrobe=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"CRTC_TYPE")==0) { + ae->snapshot.crtcstate.model=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"CRTC_HCC")==0) { + ae->snapshot.crtcstate.HCC=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"CRTC_CLC")==0) { + ae->snapshot.crtcstate.CLC=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"CRTC_RLC")==0) { + ae->snapshot.crtcstate.RLC=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"CRTC_VAC")==0) { // Vertical Total Adjust Counter + ae->snapshot.crtcstate.VTC=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"CRTC_HSWC")==0) { + ae->snapshot.crtcstate.HSC=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"CRTC_VSWC")==0) { + ae->snapshot.crtcstate.VSC=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"CRTC_STATE")==0) { + ae->snapshot.crtcstate.flags=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"GA_VSC")==0) { + ae->snapshot.vsyncdelay=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"GA_ISC")==0) { + ae->snapshot.interruptscanlinecounter=myvalue; + } else if (strcmp(ae->wl[ae->idx].w,"INT_REQ")==0) { + ae->snapshot.interruptrequestflag=myvalue; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SNASET directive unknown non array settings\n"); + } + } else if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + /* index value */ + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + idx=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); + + /* parameter value */ + ExpressionFastTranslate(ae,&ae->wl[ae->idx+2].w,0); + myvalue=RoundComputeExpression(ae,ae->wl[ae->idx+2].w,ae->codeadr,0,0); + + if (strcmp(ae->wl[ae->idx].w,"GA_PAL")==0) { + if (idx>=0 && idx<17) { + ae->snapshot.gatearray.palette[idx]=myvalue; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SNASET directive needs [0-16] index for GA_PAL\n"); + } + } else if (strcmp(ae->wl[ae->idx].w,"CRTC_REG")==0) { + if (idx>=0 && idx<18) { + ae->snapshot.crtc.registervalue[idx]=myvalue; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SNASET directive needs [0-17] index for CRTC_REG\n"); + } + } else if (strcmp(ae->wl[ae->idx].w,"PSG_REG")==0) { + if (idx>=0 && idx<16) { + ae->snapshot.psg.registervalue[idx]=myvalue; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SNASET directive needs [0-15] index for PSG_REG\n"); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SNASET directive unknown array settings\n"); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SNASET directive need 2 or 3 parameters (see documentation for more informations)\n"); + } + } + + +} + + +void __SETCPC(struct s_assenv *ae) { + int mycpc; + + rasm_printf(ae,KWARNING"[%s:%d] Warning: SETCPC is deprecated, use SNASET CPC_TYPE, instead\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + + if (!ae->forcecpr && !ae->forceROM && !ae->forcezx) { + ae->forcesnapshot=1; + } else { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: Cannot SETCPC when already in ZX/ROM/cartridge output\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + if (ae->erronwarn) MaxError(ae); + } + } + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + mycpc=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); + ae->idx++; + switch (mycpc) { + case 0: + case 1: + case 2: + case 4: + case 5: + case 6: + ae->snapshot.CPCType=mycpc; + break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SETCPC directive has wrong value (0,1,2,4,5,6 only)\n"); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SETCPC directive need one integer parameter\n"); + } +} +void __SETCRTC(struct s_assenv *ae) { + int mycrtc; + + rasm_printf(ae,KWARNING"[%s:%d] Warning: SETCRTC is deprecated, use SNASET CRTC_TYPE, instead\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + + if (!ae->forcecpr && !ae->forcezx && !ae->forceROM) { + ae->forcesnapshot=1; + } else { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: Cannot SETCRTC when already in ZX/ROM/cartridge output\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + if (ae->erronwarn) MaxError(ae); + } + } + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + mycrtc=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SETCRTC directive need one integer parameter\n"); + mycrtc=0; + } + switch (mycrtc) { + case 0: + case 1: + case 2: + case 3: + case 4: + ae->snapshot.crtcstate.model=mycrtc; + break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SETCRTC directive has wrong value (0,1,2,3,4 only)\n"); + } +} + + +void __LIST(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LIST Winape directive does not need parameter\n"); + } +} +void __NOLIST(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"NOLIST Winape directive does not need parameter\n"); + } +} + +void __BRK(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BRK Winape directive does not need parameter\n"); + } else { + ___output(ae,0xED); + ___output(ae,0xFF); + } +} + +void __STOP(struct s_assenv *ae) { + rasm_printf(ae,"[%s:%d] STOP assembling requested\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + while (ae->wl[ae->idx].t!=2) ae->idx++; + ae->idx--; + ae->stop=1; +} + +void __DELAYED_PRINT(struct s_assenv *ae) { + IntArrayAddDynamicValueConcat(&ae->dprint_idx,&ae->idprint,&ae->mdprint,ae->idx); + /* skip parameters */ + while (ae->wl[ae->idx].t!=1) { + ae->idx++; + } +} + +void __PRINT(struct s_assenv *ae) { + while (ae->wl[ae->idx].t!=1) { + if (!StringIsQuote(ae->wl[ae->idx+1].w)) { + char *string2print=NULL; + int hex=0,bin=0,entier=0; + + if (strncmp(ae->wl[ae->idx+1].w,"{HEX}",5)==0) { + string2print=TxtStrDup(ae->wl[ae->idx+1].w+5); + hex=1; + } else if (strncmp(ae->wl[ae->idx+1].w,"{HEX2}",6)==0) { + string2print=TxtStrDup(ae->wl[ae->idx+1].w+6); + hex=2; + } else if (strncmp(ae->wl[ae->idx+1].w,"{HEX4}",6)==0) { + string2print=TxtStrDup(ae->wl[ae->idx+1].w+6); + hex=4; + } else if (strncmp(ae->wl[ae->idx+1].w,"{HEX8}",6)==0) { + string2print=TxtStrDup(ae->wl[ae->idx+1].w+6); + hex=8; + } else if (strncmp(ae->wl[ae->idx+1].w,"{BIN}",5)==0) { + string2print=TxtStrDup(ae->wl[ae->idx+1].w+5); + bin=1; + } else if (strncmp(ae->wl[ae->idx+1].w,"{BIN8}",6)==0) { + string2print=TxtStrDup(ae->wl[ae->idx+1].w+6); + bin=8; + } else if (strncmp(ae->wl[ae->idx+1].w,"{BIN16}",7)==0) { + string2print=TxtStrDup(ae->wl[ae->idx+1].w+7); + bin=16; + } else if (strncmp(ae->wl[ae->idx+1].w,"{BIN32}",7)==0) { + string2print=TxtStrDup(ae->wl[ae->idx+1].w+7); + bin=32; + } else if (strncmp(ae->wl[ae->idx+1].w,"{INT}",5)==0) { + string2print=TxtStrDup(ae->wl[ae->idx+1].w+5); + entier=1; + } else if (strncmp(ae->wl[ae->idx+1].w,"{INT",4)==0 && ae->wl[ae->idx+1].w[4] && ae->wl[ae->idx+1].w[5]=='}') { + string2print=TxtStrDup(ae->wl[ae->idx+1].w+6); + entier=ae->wl[ae->idx+1].w[4]-'0'; + if (entier<2 || entier>5) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"invalid prefix, must be from INT2 to INT5\n"); + entier=5; + } + } else { + string2print=TxtStrDup(ae->wl[ae->idx+1].w); + } + + ExpressionFastTranslate(ae,&string2print,1); + if (hex) { + int zv; + zv=RoundComputeExpressionCore(ae,string2print,ae->codeadr,0); + switch (hex) { + case 1: + if (zv&0xFFFFFF00) { + if (zv&0xFFFF0000) { + rasm_printf(ae,"#%-8.08X ",zv); + } else { + rasm_printf(ae,"#%-4.04X ",zv); + } + } else { + rasm_printf(ae,"#%-2.02X ",zv); + } + break; + case 2:rasm_printf(ae,"#%-2.02X ",zv);break; + case 4:rasm_printf(ae,"#%-4.04X ",zv);break; + case 8:rasm_printf(ae,"#%-8.08X ",zv);break; + } + } else if (bin) { + int zv,d; + zv=RoundComputeExpressionCore(ae,string2print,ae->codeadr,0); + /* remove useless sign bits */ + if (bin<32 && (zv&0xFFFF0000)==0xFFFF0000) { + zv&=0xFFFF; + } + switch (bin) { + case 1:if (zv&0xFF00) d=15; else d=7;break; + case 8:d=7;break; + case 16:d=15;break; + case 32:d=31;break; + } + rasm_printf(ae,"%%"); + for (;d>=0;d--) { + if ((zv>>d)&1) rasm_printf(ae,"1"); else rasm_printf(ae,"0"); + } + rasm_printf(ae," "); + } else if (entier) { + rasm_printf(ae,"%0*d ",entier,(int)RoundComputeExpressionCore(ae,string2print,ae->codeadr,0)); + } else { + rasm_printf(ae,"%.2lf ",ComputeExpressionCore(ae,string2print,ae->codeadr,0)); + } + MemFree(string2print); + } else { + char *varbuffer; + int lm,touched; + lm=strlen(ae->wl[ae->idx+1].w)-2; + if (lm) { + varbuffer=MemMalloc(lm+2); + sprintf(varbuffer,"%-*.*s ",lm,lm,ae->wl[ae->idx+1].w+1); + /* need to upper case tags */ + for (lm=touched=0;varbuffer[lm];lm++) { + if (varbuffer[lm]=='{') touched++; else if (varbuffer[lm]=='}') touched--; else if (touched) varbuffer[lm]=toupper(varbuffer[lm]); + } + /* translate tag will check tag consistency */ + varbuffer=TranslateTag(ae,varbuffer,&touched,1,E_TAGOPTION_REMOVESPACE); + varbuffer=TxtReplace(varbuffer,"\\b","\b",0); + varbuffer=TxtReplace(varbuffer,"\\v","\v",0); + varbuffer=TxtReplace(varbuffer,"\\f","\f",0); + varbuffer=TxtReplace(varbuffer,"\\r","\r",0); + varbuffer=TxtReplace(varbuffer,"\\n","\n",0); + varbuffer=TxtReplace(varbuffer,"\\t","\t",0); + rasm_printf(ae,"%s ",varbuffer); + MemFree(varbuffer); + } + } + ae->idx++; + } + rasm_printf(ae,"\n"); +} + +void __FAIL(struct s_assenv *ae) { + __PRINT(ae); + __STOP(ae); + MaxError(ae); +} + +void __CONFINE(struct s_assenv *ae) { + int aval,ifill=0,warning=0,enforce=0; + + if (ae->io) { + ae->orgzone[ae->io-1].memend=ae->outputadr; // mandatory but why??? + } + if (!ae->wl[ae->idx].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + aval=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0)-1; + ae->idx++; + while (!ae->wl[ae->idx].t) { + if (strcmp(ae->wl[ae->idx+1].w,"ENFORCE")==0) { + warning=1; + } else if (strcmp(ae->wl[ae->idx+1].w,"WARNING")==0) { + warning=1; + } else /* confine with fill ? */ { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + ifill=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); + if (ifill<0 || ifill>255) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ALIGN fill value must be 0 to 255\n"); + ifill=0; + } + } + ae->idx++; + } + if (aval<1 || aval>256) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CONFINE size must be in [2-256] interval\n"); + aval=1; + } + /* touch codeadr only if needed */ + if (((ae->codeadr+aval)&0xFF00)!=(ae->codeadr&0xFF00)) { + if (!ae->nowarning || warning || enforce) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: confinement overflows %d byte%s, loss of %d byte%s\n",GetCurrentFile(ae),ae->wl[ae->idx].l, + ((ae->codeadr+aval)&0xFF)+1,(((ae->codeadr+aval)&0xFF)+1)>1?"s":"", + aval-((ae->codeadr+aval)&0xFF)-1,aval-((ae->codeadr+aval)&0xFF)-1>1?"s":""); + if (ae->erronwarn || enforce) MaxError(ae); + } + /* physical ALIGN fill bytes */ + while ((ae->codeadr&0xFF)!=0) { + ___output(ae,ifill); + ae->nop+=1; + } + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CONFINE [,fill] directive need one or two integers parameters\n"); + } +} + +void __ALIGN(struct s_assenv *ae) { + int aval,ifill=-1; + + if (ae->io) { + ae->orgzone[ae->io-1].memend=ae->outputadr; + } + if (!ae->wl[ae->idx].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + aval=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); + ae->idx++; + /* align with fill ? */ + if (!ae->wl[ae->idx].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + ifill=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); + ae->idx++; + if (ifill<0 || ifill>255) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ALIGN fill value must be 0 to 255\n"); + ifill=0; + } + } + + if (aval<1 || aval>65535) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ALIGN boundary must be greater than zero and lower than 65536\n"); + aval=1; + } + + /* touch codeadr only if address is misaligned */ + if (ae->codeadr%aval) { + if (ifill==-1) { + /* virtual ALIGN is moving outputadr the same value as codeadr move */ + ae->outputadr=ae->outputadr-(ae->codeadr%aval)+aval; + ae->codeadr=ae->codeadr-(ae->codeadr%aval)+aval; + } else { + /* physical ALIGN fill bytes */ + while (ae->codeadr%aval) { + ___output(ae,ifill); + ae->nop+=1; + } + } + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ALIGN [,fill] directive need one or two integers parameters\n"); + } +} + +void ___internal_skip_loop_block(struct s_assenv *ae, int eloopstyle) { + int *loopstyle=NULL; + int iloop=0,mloop=0; + int cidx; + + cidx=ae->idx+2; + + IntArrayAddDynamicValueConcat(&loopstyle,&iloop,&mloop,eloopstyle); + /* look for WEND */ + while (iloop) { + if (strcmp(ae->wl[cidx].w,"REPEAT")==0) { + if (ae->wl[cidx].t) { + IntArrayAddDynamicValueConcat(&loopstyle,&iloop,&mloop,E_LOOPSTYLE_REPEATUNTIL); + } else if (ae->wl[cidx+1].t) { + IntArrayAddDynamicValueConcat(&loopstyle,&iloop,&mloop,E_LOOPSTYLE_REPEATN); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid REPEAT syntax\n"); + } + } else if (strcmp(ae->wl[cidx].w,"WHILE")==0) { + if (!ae->wl[cidx].t && ae->wl[cidx+1].t) { + IntArrayAddDynamicValueConcat(&loopstyle,&iloop,&mloop,E_LOOPSTYLE_WHILE); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid WHILE syntax\n"); + } + } else if (strcmp(ae->wl[cidx].w,"WEND")==0) { + iloop--; + if (iloop<0) { + iloop=0; + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WEND encountered that was not expected\n"); + } else if (loopstyle[iloop]!=E_LOOPSTYLE_WHILE) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WEND encountered but expecting %s\n",loopstyle[iloop]==E_LOOPSTYLE_REPEATN?"REND":"UNTIL"); + } + } else if (strcmp(ae->wl[cidx].w,"REND")==0) { + iloop--; + if (iloop<0) { + iloop=0; + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"REND encountered that was not expected\n"); + } else if (loopstyle[iloop]!=E_LOOPSTYLE_REPEATN) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"REND encountered but expecting %s\n",loopstyle[iloop]==E_LOOPSTYLE_REPEATUNTIL?"UNTIL":"WEND"); + } + } else if (strcmp(ae->wl[cidx].w,"UNTIL")==0) { + iloop--; + if (iloop<0) { + iloop=0; + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"UNTIL encountered that was not expected\n"); + } else if (loopstyle[iloop]!=E_LOOPSTYLE_REPEATUNTIL) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"UNTIL encountered but expecting %s\n",loopstyle[iloop]==E_LOOPSTYLE_REPEATN?"REND":"WEND"); + } + } + while (!ae->wl[cidx].t) cidx++; + cidx++; + } + MemFree(loopstyle); + ae->idx=cidx-1; +} + +void __WHILE(struct s_assenv *ae) { + struct s_whilewend whilewend={0}; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + if (!ComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,2)) { + /* skip while block */ + ___internal_skip_loop_block(ae,E_LOOPSTYLE_WHILE); + return; + } else { + + /*************************************************/ + /********* PUSH Global on Stack ******************/ + /*************************************************/ + PushGlobal(ae); + + ae->idx++; + whilewend.start=ae->idx; + whilewend.cpt=0; + whilewend.value=ae->whilecounter; + whilewend.maxim=ae->imacropos; + whilewend.while_counter=1; + ae->whilecounter++; + /* pour gérer les macros situés dans le while précedent après un repeat/while courant */ + if (ae->iw) whilewend.maxim=ae->whilewend[ae->iw-1].maxim; + if (ae->ir && ae->repeat[ae->ir-1].maxim>whilewend.maxim) whilewend.maxim=ae->repeat[ae->ir-1].maxim; + ObjectArrayAddDynamicValueConcat((void**)&ae->whilewend,&ae->iw,&ae->mw,&whilewend,sizeof(whilewend)); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is WHILE \n"); + } +} +void __WEND(struct s_assenv *ae) { + if (ae->iw>0) { + if (ae->wl[ae->idx].t==1) { + if (ComputeExpression(ae,ae->wl[ae->whilewend[ae->iw-1].start].w,ae->codeadr,0,2)) { + if (ae->whilewend[ae->iw-1].while_counter>65536) { + + /*************************************************/ + /********* POP Global on Stack *******************/ + /*************************************************/ + PopGlobal(ae); + + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Bypass infinite WHILE loop\n"); + ae->iw--; + /* refresh macro check index */ + if (ae->iw) ae->imacropos=ae->whilewend[ae->iw-1].maxim; + } else { + ae->whilewend[ae->iw-1].cpt++; /* for local label */ + ae->whilewend[ae->iw-1].while_counter++; + ae->idx=ae->whilewend[ae->iw-1].start; + /* refresh macro check index */ + ae->imacropos=ae->whilewend[ae->iw-1].maxim; + } + } else { + + /*************************************************/ + /********* POP Global on Stack *******************/ + /*************************************************/ + PopGlobal(ae); + + ae->iw--; + /* refresh macro check index */ + if (ae->iw) ae->imacropos=ae->whilewend[ae->iw-1].maxim; + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WEND does not need any parameter\n"); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WEND encounter whereas there is no referent WHILE\n"); + } +} + +void __STARTINGINDEX(struct s_assenv *ae) { + if (ae->wl[ae->idx].t==0) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + ae->repeat_start=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,0,0,0); + ae->idx++; + if (ae->wl[ae->idx].t==0) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + ae->repeat_increment=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,0,0,0); + ae->idx++; + } + } else { + ae->repeat_start=1; + ae->repeat_increment=1; + } +} + +void __REPEAT(struct s_assenv *ae) { + struct s_repeat currepeat={0}; + struct s_expr_dico *rvar; + int crc; + + if (ae->wl[ae->idx+1].t!=2) { + if (ae->wl[ae->idx].t==0) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + currepeat.cpt=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,0,0,0); + + if (!currepeat.cpt) { + /* skip repeat block */ + ___internal_skip_loop_block(ae,E_LOOPSTYLE_REPEATN); + return; + } else if (currepeat.cpt<1 || currepeat.cpt>65536) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Repeat value (%d) must be from 1 to 65535. Skipping block\n",currepeat.cpt); + ___internal_skip_loop_block(ae,E_LOOPSTYLE_REPEATN); + return; + } + ae->idx++; + if (ae->wl[ae->idx].t==0) { + double vstart; + ae->idx++; + + // default + currepeat.varincrement=ae->repeat_increment; + vstart=ae->repeat_start; + + /* additionnal options */ + if (ae->wl[ae->idx].t==0) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + vstart=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,0,0,0); + if (ae->wl[ae->idx+1].t==0) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+2].w,0); + currepeat.varincrement=RoundComputeExpression(ae,ae->wl[ae->idx+2].w,0,0,0); + } + } + + /* la variable peut exister -> OK */ + crc=GetCRC(ae->wl[ae->idx].w); + if ((rvar=SearchDico(ae,ae->wl[ae->idx].w,crc))!=NULL) { + rvar->v=vstart; + } else { + /* mais ne peut être un label ou un alias */ + ExpressionSetDicoVar(ae,ae->wl[ae->idx].w,vstart,0); + } + currepeat.repeatvar=ae->wl[ae->idx].w; + currepeat.repeatcrc=crc; + // adjust + while (ae->wl[ae->idx].t==0) ae->idx++; + } + currepeat.start=ae->idx-1; + } else { + currepeat.start=ae->idx; + currepeat.cpt=-1; + } + + /*************************************************/ + /********* PUSH Global on Stack ******************/ + /*************************************************/ + PushGlobal(ae); + + currepeat.value=ae->repeatcounter; + currepeat.repeat_counter=1; + ae->repeatcounter++; + /* pour gérer les macros situés dans le repeat précedent après le repeat courant */ + if (ae->ir) currepeat.maxim=ae->repeat[ae->ir-1].maxim; + if (ae->iw && ae->whilewend[ae->iw-1].maxim>currepeat.maxim) currepeat.maxim=ae->whilewend[ae->iw-1].maxim; + if (ae->imacropos>currepeat.maxim) currepeat.maxim=ae->imacropos; + ObjectArrayAddDynamicValueConcat((void**)&ae->repeat,&ae->ir,&ae->mr,&currepeat,sizeof(currepeat)); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"wrong REPEAT usage\n"); + } +} + +void __REND(struct s_assenv *ae) { + struct s_expr_dico *rvar; + if (ae->ir>0) { + if (ae->repeat[ae->ir-1].cpt==-1) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"REND encounter whereas referent REPEAT was waiting for UNTIL\n"); + } else { + ae->repeat[ae->ir-1].cpt--; + ae->repeat[ae->ir-1].repeat_counter++; + if ((rvar=SearchDico(ae,ae->repeat[ae->ir-1].repeatvar,ae->repeat[ae->ir-1].repeatcrc))!=NULL) { + rvar->v+=ae->repeat[ae->ir-1].varincrement; // LEGACY rvar->v=ae->repeat[ae->ir-1].repeat_counter; + } + if (ae->repeat[ae->ir-1].cpt) { + ae->idx=ae->repeat[ae->ir-1].start; + /* refresh macro check index */ + ae->imacropos=ae->repeat[ae->ir-1].maxim; + } else { + ae->ir--; + /* refresh macro check index */ + if (ae->ir) ae->imacropos=ae->repeat[ae->ir-1].maxim; + + /*************************************************/ + /********* POP Global on Stack *******************/ + /*************************************************/ + PopGlobal(ae); + + } + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"REND encounter whereas there is no referent REPEAT\n"); + } +} + +void __UNTIL(struct s_assenv *ae) { + if (ae->ir>0) { + if (ae->repeat[ae->ir-1].cpt>=0) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"[%s:%d] UNTIL encounter whereas referent REPEAT n was waiting for REND\n"); + } else { + if (ae->wl[ae->idx].t==0 && ae->wl[ae->idx+1].t==1) { + ae->repeat[ae->ir-1].repeat_counter++; + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + if (!ComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,2)) { + if (ae->repeat[ae->ir-1].repeat_counter>65536) { + + /*************************************************/ + /********* POP Global on Stack *******************/ + /*************************************************/ + PopGlobal(ae); + + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Bypass infinite REPEAT loop\n"); + ae->ir--; + /* refresh macro check index */ + if (ae->ir) ae->imacropos=ae->repeat[ae->ir-1].maxim; + } else { + ae->idx=ae->repeat[ae->ir-1].start; + ae->repeat[ae->ir-1].cpt--; /* for local label */ + /* refresh macro check index */ + ae->imacropos=ae->repeat[ae->ir-1].maxim; + } + } else { + + /*************************************************/ + /********* POP Global on Stack *******************/ + /*************************************************/ + PopGlobal(ae); + + ae->ir--; + /* refresh macro check index */ + if (ae->ir) ae->imacropos=ae->repeat[ae->ir-1].maxim; + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"UNTIL need one expression/evaluation as parameter\n"); + } + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"UNTIL encounter whereas there is no referent REPEAT\n"); + } +} + +void __ASSERT(struct s_assenv *ae) { + char Dot3[4]; + int rexpr; + + if (!ae->wl[ae->idx].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + if (strlen(ae->wl[ae->idx+1].w)>29) strcpy(Dot3,"..."); else strcpy(Dot3,""); + rexpr=!!RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,1); + if (!rexpr) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx+1].l,"ASSERT %.29s%s failed with ",ae->wl[ae->idx+1].w,Dot3); + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,1); + rasm_printf(ae,"%s\n",ae->wl[ae->idx+1].w); + if (!ae->wl[ae->idx+1].t) { + ae->idx++; + rasm_printf(ae,"-> "); + __PRINT(ae); + } + __STOP(ae); + } else { + while (!ae->wl[ae->idx].t) ae->idx++; + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ASSERT need one expression\n"); + } +} + +void __IF(struct s_assenv *ae) { + struct s_ifthen ifthen={0}; + int rexpr; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + rexpr=!!RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,1); + ifthen.v=rexpr; + ifthen.filename=GetCurrentFile(ae); + ifthen.line=ae->wl[ae->idx].l; + ifthen.type=E_IFTHEN_TYPE_IF; + ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IF need one expression\n"); + } +} + +void __IF_light(struct s_assenv *ae) { + struct s_ifthen ifthen={0}; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + /* does not need to compute the value in shadow execution */ + ifthen.v=0; + ifthen.filename=GetCurrentFile(ae); + ifthen.line=ae->wl[ae->idx].l; + ifthen.type=E_IFTHEN_TYPE_IF; + ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IF need one expression\n"); + } +} + +/* test if a label or a variable where used before */ +void __IFUSED(struct s_assenv *ae) { + struct s_ifthen ifthen={0}; + int rexpr,crc; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + crc=GetCRC(ae->wl[ae->idx+1].w); + if ((SearchDico(ae,ae->wl[ae->idx+1].w,crc))!=NULL) { + rexpr=1; + } else { + char *labelmodule=NULL; + // first look for module label! + if (ae->module) { + labelmodule=MemMalloc(ae->modulen+2+strlen(ae->wl[ae->idx+1].w)); + strcpy(labelmodule,ae->module); + strcat(labelmodule,ae->module_separator); + strcat(labelmodule,ae->wl[ae->idx+1].w); + } + if (ae->module && (SearchLabel(ae,labelmodule,GetCRC(labelmodule)))!=NULL) { + rexpr=1; + } else if ((SearchLabel(ae,ae->wl[ae->idx+1].w,crc))!=NULL) { + rexpr=1; + } else if ((SearchAlias(ae,crc,ae->wl[ae->idx+1].w))!=-1) { + rexpr=1; + } else { + rexpr=SearchUsed(ae,ae->wl[ae->idx+1].w,crc); + } + if (labelmodule) MemFree(labelmodule); + } + ifthen.v=rexpr; + ifthen.filename=GetCurrentFile(ae); + ifthen.line=ae->wl[ae->idx].l; + ifthen.type=E_IFTHEN_TYPE_IFUSED; + ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IFUSED need one variable or label\n"); + } +} +void __IFNUSED(struct s_assenv *ae) { + __IFUSED(ae); + ae->ifthen[ae->ii-1].v=1-ae->ifthen[ae->ii-1].v; + ae->ifthen[ae->ii-1].type=E_IFTHEN_TYPE_IFNUSED; +} +void __IFUSED_light(struct s_assenv *ae) { + struct s_ifthen ifthen={0}; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ifthen.v=0; + ifthen.filename=GetCurrentFile(ae); + ifthen.line=ae->wl[ae->idx].l; + ifthen.type=E_IFTHEN_TYPE_IFUSED; + ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IFUSED need one variable or label\n"); + } +} +void __IFNUSED_light(struct s_assenv *ae) { + __IFUSED_light(ae); + ae->ifthen[ae->ii-1].type=E_IFTHEN_TYPE_IFNUSED; +} + +/* test if a label or a variable exists */ +void __IFDEF(struct s_assenv *ae) { + struct s_ifthen ifthen={0}; + int rexpr,crc; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + crc=GetCRC(ae->wl[ae->idx+1].w); + if ((SearchDico(ae,ae->wl[ae->idx+1].w,crc))!=NULL) { + rexpr=1; + } else { + char *labelmodule=NULL; + // first look for module label! + if (ae->module) { + labelmodule=MemMalloc(ae->modulen+2+strlen(ae->wl[ae->idx+1].w)); + strcpy(labelmodule,ae->module); + strcat(labelmodule,ae->module_separator); + strcat(labelmodule,ae->wl[ae->idx+1].w); + } + if (labelmodule && (SearchLabel(ae,labelmodule,GetCRC(labelmodule)))!=NULL) { + rexpr=1; + } else if ((SearchLabel(ae,ae->wl[ae->idx+1].w,crc))!=NULL) { + rexpr=1; + } else if ((SearchAlias(ae,crc,ae->wl[ae->idx+1].w))!=-1) { + rexpr=1; + } else if (SearchMacro(ae,crc,ae->wl[ae->idx+1].w)>=0) { + rexpr=1; + } else { + rexpr=0; + } + if (labelmodule) MemFree(labelmodule); + } + ifthen.v=rexpr; + ifthen.filename=GetCurrentFile(ae); + ifthen.line=ae->wl[ae->idx].l; + ifthen.type=E_IFTHEN_TYPE_IFDEF; + ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IFDEF need one variable or label\n"); + } +} +void __IFDEF_light(struct s_assenv *ae) { + struct s_ifthen ifthen={0}; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ifthen.v=0; + ifthen.filename=GetCurrentFile(ae); + ifthen.line=ae->wl[ae->idx].l; + ifthen.type=E_IFTHEN_TYPE_IFDEF; + ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IFDEF need one variable or label\n"); + } +} +void __IFNDEF(struct s_assenv *ae) { + struct s_ifthen ifthen={0}; + int rexpr,crc; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + crc=GetCRC(ae->wl[ae->idx+1].w); + if ((SearchDico(ae,ae->wl[ae->idx+1].w,crc))!=NULL) { + rexpr=0; + } else { + char *labelmodule=NULL; + // first look for module label! + if (ae->module) { + labelmodule=MemMalloc(ae->modulen+2+strlen(ae->wl[ae->idx+1].w)); + strcpy(labelmodule,ae->module); + strcat(labelmodule,ae->module_separator); + strcat(labelmodule,ae->wl[ae->idx+1].w); + } + if (ae->module && (SearchLabel(ae,labelmodule,GetCRC(labelmodule)))!=NULL) { + rexpr=0; + } else if ((SearchLabel(ae,ae->wl[ae->idx+1].w,crc))!=NULL) { + rexpr=0; + } else if ((SearchAlias(ae,crc,ae->wl[ae->idx+1].w))!=-1) { + rexpr=0; + } else if (SearchMacro(ae,crc,ae->wl[ae->idx+1].w)>=0) { + rexpr=0; + } else { + rexpr=1; + } + if (labelmodule) MemFree(labelmodule); + } + ifthen.v=rexpr; + ifthen.filename=GetCurrentFile(ae); + ifthen.line=ae->wl[ae->idx].l; + ifthen.type=E_IFTHEN_TYPE_IFNDEF; + ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IFNDEF need one variable or label\n"); + } +} +void __IFNDEF_light(struct s_assenv *ae) { + struct s_ifthen ifthen={0}; + + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ifthen.v=0; + ifthen.filename=GetCurrentFile(ae); + ifthen.line=ae->wl[ae->idx].l; + ifthen.type=E_IFTHEN_TYPE_IFNDEF; + ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IFNDEF need one variable or label\n"); + } +} + +void __UNDEF(struct s_assenv *ae) { + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + /* no error when the variable to UNDEF does not exist */ + DelDico(ae,ae->wl[ae->idx+1].w,GetCRC(ae->wl[ae->idx+1].w)); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is UNDEF \n"); + } + +} + + +void __SWITCH(struct s_assenv *ae) { + struct s_switchcase curswitch={0}; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + /* switch store the value */ + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + curswitch.refval=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,1); + ObjectArrayAddDynamicValueConcat((void**)&ae->switchcase,&ae->isw,&ae->msw,&curswitch,sizeof(curswitch)); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SWITCH need one expression\n"); + } +} +void __CASE(struct s_assenv *ae) { + int rexpr; + + if (ae->isw) { + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + rexpr=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,1); + + if (ae->switchcase[ae->isw-1].refval==rexpr) { + ae->switchcase[ae->isw-1].execute=1; + ae->switchcase[ae->isw-1].casematch=1; + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CASE not need one parameter\n"); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CASE encounter whereas there is no referent SWITCH\n"); + } +} +void __DEFAULT(struct s_assenv *ae) { + + if (ae->isw) { + if (ae->wl[ae->idx].t==1) { + /* aucun match avant, on active, sinon on laisse tel quel */ + if (!ae->switchcase[ae->isw-1].casematch) { + ae->switchcase[ae->isw-1].execute=1; + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFAULT does not need parameter\n"); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFAULT encounter whereas there is no referent SWITCH\n"); + } +} +void __BREAK(struct s_assenv *ae) { + + if (ae->isw) { + if (ae->wl[ae->idx].t==1) { + ae->switchcase[ae->isw-1].execute=0; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BREAK does not need parameter\n"); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BREAK encounter whereas there is no referent SWITCH\n"); + } +} +void __SWITCH_light(struct s_assenv *ae) { + struct s_switchcase curswitch={0}; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + /* shadow execution */ + curswitch.refval=0; + curswitch.execute=0; + ObjectArrayAddDynamicValueConcat((void**)&ae->switchcase,&ae->isw,&ae->msw,&curswitch,sizeof(curswitch)); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SWITCH need one expression\n"); + } +} +void __CASE_light(struct s_assenv *ae) { + if (ae->isw) { + /* shadowed execution */ + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CASE encounter whereas there is no referent SWITCH\n"); + } +} +void __DEFAULT_light(struct s_assenv *ae) { + + if (ae->isw) { + /* shadowed execution */ + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFAULT encounter whereas there is no referent SWITCH\n"); + } +} +void __BREAK_light(struct s_assenv *ae) { + if (ae->isw) { + /* shadowed execution */ + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BREAK encounter whereas there is no referent SWITCH\n"); + } +} +void __ENDSWITCH(struct s_assenv *ae) { + if (ae->isw) { + if (ae->wl[ae->idx].t==1) { + ae->isw--; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ENDSWITCH does not need any parameter\n"); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ENDSWITCH encounter whereas there is no referent SWITCH\n"); + } +} + +void __IFNOT(struct s_assenv *ae) { + struct s_ifthen ifthen={0}; + int rexpr; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + rexpr=!RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,1); + ifthen.v=rexpr; + ifthen.filename=GetCurrentFile(ae); + ifthen.line=ae->wl[ae->idx].l; + ifthen.type=E_IFTHEN_TYPE_IFNOT; + ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); + //IntArrayAddDynamicValueConcat(&ae->ifthen,&ae->ii,&ae->mi,rexpr); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IFNOT need one expression\n"); + } +} +void __IFNOT_light(struct s_assenv *ae) { + struct s_ifthen ifthen={0}; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ifthen.v=0; + ifthen.filename=GetCurrentFile(ae); + ifthen.line=ae->wl[ae->idx].l; + ifthen.type=E_IFTHEN_TYPE_IFNOT; + ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); + //IntArrayAddDynamicValueConcat(&ae->ifthen,&ae->ii,&ae->mi,rexpr); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IFNOT need one expression\n"); + } +} + +void __ELSE(struct s_assenv *ae) { + if (ae->ii) { + if (ae->wl[ae->idx].t==1) { + /* ELSE a executer seulement si celui d'avant est a zero */ + switch (ae->ifthen[ae->ii-1].v) { + case -1:break; + case 0:ae->ifthen[ae->ii-1].v=1;break; + case 1:ae->ifthen[ae->ii-1].v=0;break; + } + ae->ifthen[ae->ii-1].type=E_IFTHEN_TYPE_ELSE; + ae->ifthen[ae->ii-1].line=ae->wl[ae->idx].l; + ae->ifthen[ae->ii-1].filename=GetCurrentFile(ae); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ELSE does not need any parameter\n"); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ELSE encounter whereas there is no referent IF\n"); + } +} +void __ELSEIF(struct s_assenv *ae) { + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ae->ifthen[ae->ii-1].type=E_IFTHEN_TYPE_ELSEIF; + ae->ifthen[ae->ii-1].line=ae->wl[ae->idx].l; + ae->ifthen[ae->ii-1].filename=GetCurrentFile(ae); + if (ae->ifthen[ae->ii-1].v) { + /* il faut signifier aux suivants qu'on va jusqu'au ENDIF */ + ae->ifthen[ae->ii-1].v=-1; + } else { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + ae->ifthen[ae->ii-1].v=!!RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,1); + } + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ELSEIF need one expression\n"); + } +} +void __ELSEIF_light(struct s_assenv *ae) { + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ae->ifthen[ae->ii-1].type=E_IFTHEN_TYPE_ELSEIF; + ae->ifthen[ae->ii-1].line=ae->wl[ae->idx].l; + ae->ifthen[ae->ii-1].filename=GetCurrentFile(ae); + if (ae->ifthen[ae->ii-1].v) { + /* il faut signifier aux suivants qu'on va jusqu'au ENDIF */ + ae->ifthen[ae->ii-1].v=-1; + } else { + ae->ifthen[ae->ii-1].v=0; + } + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ELSEIF need one expression\n"); + } +} +void __ENDIF(struct s_assenv *ae) { + if (ae->ii) { + if (ae->wl[ae->idx].t==1) { + ae->ii--; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ENDIF does not need any parameter\n"); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ENDIF encounter whereas there is no referent IF\n"); + } +} + +void __internal_PROTECT(struct s_assenv *ae, int memstart, int memend) { + struct s_orgzone orgzone={0}; + + /* add a fake ORG zone */ + ObjectArrayAddDynamicValueConcat((void**)&ae->orgzone,&ae->io,&ae->mo,&orgzone,sizeof(orgzone)); + /* then switch it with the current ORG */ + orgzone=ae->orgzone[ae->io-2]; + ae->orgzone[ae->io-2].memstart=memstart; + ae->orgzone[ae->io-2].memend=memend; + ae->orgzone[ae->io-2].ibank=ae->activebank; + ae->orgzone[ae->io-2].protect=1; + ae->orgzone[ae->io-1]=orgzone; +} + +void __PROTECT(struct s_assenv *ae) { + int memstart,memend; + + if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + ExpressionFastTranslate(ae,&ae->wl[ae->idx+2].w,0); + memstart=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,0,0,0); + memend=RoundComputeExpression(ae,ae->wl[ae->idx+2].w,0,0,0); + __internal_PROTECT(ae,memstart,memend); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"PROTECT need two parameters: startadr,endadr\n"); + } +} + +void ___org_close(struct s_assenv *ae) { + if (ae->lz>=0 && ae->lzsection[ae->ilz-1].lzversion) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot ORG inside a LZ section\n"); + return; + } + __internal_UpdateLZBlockIfAny(ae); + /* close current ORG */ + if (ae->io) { + ae->orgzone[ae->io-1].memend=ae->outputadr; + } +} + +void ___org_new(struct s_assenv *ae, int nocode) { + struct s_orgzone orgzone={0}; + int i; + + /* check current ORG request */ + for (i=0;iio;i++) { + /* aucun contrôle sur les ORG non écrits ou en NOCODE */ + if (ae->orgzone[i].memstart!=ae->orgzone[i].memend && !ae->orgzone[i].nocode) { + if (ae->orgzone[i].ibank==ae->activebank) { + if (ae->outputadrorgzone[i].memend && ae->outputadr>=ae->orgzone[i].memstart) { + if (ae->orgzone[i].protect) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ORG located a PROTECTED section [#%04X-#%04X-B%d] file [%s] line %d\n",ae->orgzone[i].memstart,ae->orgzone[i].memend,ae->orgzone[i].ibank<32?ae->orgzone[i].ibank:0,ae->filename[ae->orgzone[i].ifile],ae->orgzone[i].iline); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ORG (output at #%04X) located in a previous ORG section [#%04X-#%04X-B%d] file [%s] line %d\n",ae->outputadr,ae->orgzone[i].memstart,ae->orgzone[i].memend,ae->orgzone[i].ibank<32?ae->orgzone[i].ibank:0,ae->filename[ae->orgzone[i].ifile],ae->orgzone[i].iline); + } + } + } + } + } + + OverWriteCheck(ae); + /* if there was a crunch block before, now closed */ + if (ae->lz>=0) { + ae->lz=-1; + } + orgzone.memstart=ae->outputadr; + orgzone.ibank=ae->activebank; + orgzone.ifile=ae->wl[ae->idx].ifile; + orgzone.iline=ae->wl[ae->idx].l; + orgzone.nocode=ae->nocode=nocode; + + if (nocode) { + ___output=___internal_output_nocode; + } else { + ___output=___internal_output; + } + + ObjectArrayAddDynamicValueConcat((void**)&ae->orgzone,&ae->io,&ae->mo,&orgzone,sizeof(orgzone)); +} + +void __ORG(struct s_assenv *ae) { + ___org_close(ae); + + if (ae->wl[ae->idx+1].t!=2) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + ae->codeadr=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->outputadr,0,0); + if (ae->codeadr<0 || ae->codeadr>0xFFFF) { + ae->codeadr=0; + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"[%s:%d] cannot ORG outside memory!\n"); + } + if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+2].w,0); + ae->outputadr=RoundComputeExpression(ae,ae->wl[ae->idx+2].w,ae->outputadr,0,0); + if (ae->outputadr<0 || ae->outputadr>0xFFFF) { + ae->outputadr=0; + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"[%s:%d] cannot ORG outside memory!\n"); + } + ae->idx+=2; + } else { + ae->outputadr=ae->codeadr; + ae->idx++; + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"[%s:%d] ORG code location[,output location]\n"); + return; + } + + ___org_new(ae,ae->nocode); + + if (ae->outputadr==ae->codeadr) ae->orgzone[ae->io-1].inplace=1; +} +void __NOCODE(struct s_assenv *ae) { + if (ae->wl[ae->idx].t==1) { + ___org_close(ae); + ae->codeadrbackup=ae->codeadr; + ae->outputadrbackup=ae->outputadr; + ___org_new(ae,1); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"NOCODE directive does not need parameter\n"); + } +} +void __CODE(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + if (strcmp(ae->wl[ae->idx+1].w,"SKIP")==0) { + ___org_close(ae); + ae->codeadr=ae->codeadrbackup; + ae->outputadr=ae->outputadrbackup; + ___org_new(ae,1); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"unknown parameter for CODE directive\n"); + } + ae->idx++; + } else if (ae->wl[ae->idx].t==1) { + ___org_close(ae); + ___org_new(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CODE directive does not need parameter\n"); + } +} +void __STRUCT(struct s_assenv *ae) { + #undef FUNC + #define FUNC "__STRUCT" + struct s_rasmstructfield rasmstructfield={0}; + struct s_rasmstruct rasmstruct={0}; + struct s_rasmstruct rasmstructalias={0}; + struct s_label curlabel={0}; + int crc,i,j,irs; + /* filler */ + int localsize,cursize; + + if (!ae->wl[ae->idx].t) { + if (ae->wl[ae->idx+1].t) { + /************************************************** + s t r u c t u r e d e c l a r a t i o n + **************************************************/ + if (!ae->getstruct) { + /* cannot be an existing label or EQU (but variable ok) */ + crc=GetCRC(ae->wl[ae->idx+1].w); + if ((SearchLabel(ae,ae->wl[ae->idx+1].w,crc))!=NULL || (SearchAlias(ae,crc,ae->wl[ae->idx+1].w))!=-1) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"STRUCT name must be different from existing labels ou aliases\n"); + } else { + ae->backup_filename=GetCurrentFile(ae); + ae->backup_line=ae->wl[ae->idx].l; + ae->backup_outputadr=ae->outputadr; + ae->backup_codeadr=ae->codeadr; + ae->getstruct=1; + /* STRUCT = NOCODE + ORG 0 */ + ___org_close(ae); + ae->codeadr=0; + ___org_new(ae,1); + /* create struct */ + rasmstruct.name=TxtStrDup(ae->wl[ae->idx+1].w); + rasmstruct.crc=GetCRC(rasmstruct.name); + ObjectArrayAddDynamicValueConcat((void **)&ae->rasmstruct,&ae->irasmstruct,&ae->mrasmstruct,&rasmstruct,sizeof(rasmstruct)); + ae->idx++; + + /* wrapper for data capture */ + instruction[ICRC_DEFB].makemnemo=_DEFB_struct;instruction[ICRC_DB].makemnemo=_DEFB_struct; + instruction[ICRC_DEFW].makemnemo=_DEFW_struct;instruction[ICRC_DW].makemnemo=_DEFW_struct; + instruction[ICRC_DEFI].makemnemo=_DEFI_struct; + instruction[ICRC_DEFF].makemnemo=_DEFF_struct;instruction[ICRC_DF].makemnemo=_DEFF_struct; + instruction[ICRC_DEFR].makemnemo=_DEFR_struct;instruction[ICRC_DR].makemnemo=_DEFR_struct; + instruction[ICRC_DEFS].makemnemo=_DEFS_struct;instruction[ICRC_DS].makemnemo=_DEFS_struct; + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"STRUCT cannot be declared inside previous opened STRUCT [%s] Line %d\n",ae->backup_filename,ae->backup_line); + } + } else { + /************************************************** + s t r u c t u r e i n s e r t i o n + **************************************************/ + int nbelem=1; +#if TRACE_STRUCT +printf("structure insertion\n"); +#endif + /* insert struct param1 in memory with name param2 */ + crc=GetCRC(ae->wl[ae->idx+1].w); + /* look for existing struct */ + for (irs=0;irsirasmstruct;irs++) { + if (ae->rasmstruct[irs].crc==crc && strcmp(ae->rasmstruct[irs].name,ae->wl[ae->idx+1].w)==0) break; + } + if (irs==ae->irasmstruct) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Unknown STRUCT %s\n",ae->wl[ae->idx+1].w); + } else { + /* create alias for sizeof */ + if (!ae->getstruct) { + if (ae->wl[ae->idx+2].w[0]=='@') { + rasmstructalias.name=MakeLocalLabel(ae,ae->wl[ae->idx+2].w,NULL); + } else { + rasmstructalias.name=TxtStrDup(ae->wl[ae->idx+2].w); + } + } else { +#if TRACE_STRUCT +printf("struct [%s] inside struct\n",ae->wl[ae->idx+2].w); +#endif + /* struct inside struct */ + rasmstructalias.name=MemMalloc(strlen(ae->rasmstruct[ae->irasmstruct-1].name)+2+strlen(ae->wl[ae->idx+2].w)); + sprintf(rasmstructalias.name,"%s.%s",ae->rasmstruct[ae->irasmstruct-1].name,ae->wl[ae->idx+2].w); + } + rasmstructalias.crc=GetCRC(rasmstructalias.name); + rasmstructalias.size=ae->rasmstruct[irs].size; + rasmstructalias.ptr=ae->codeadr; +#if TRACE_STRUCT +printf("structalias [%s] ptr=%d size=%d\n",rasmstructalias.name,rasmstructalias.ptr,rasmstructalias.size); +#endif + /* extra parameter to declare an array? */ + if (!ae->wl[ae->idx+2].t && !StringIsQuote(ae->wl[ae->idx+3].w)) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+3].w,0); + nbelem=RoundComputeExpression(ae,ae->wl[ae->idx+3].w,ae->outputadr,0,0); + if (nbelem<1) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Struct array need a positive number of elements!\n"); + nbelem=1; + } + ae->idx++; + } + rasmstructalias.nbelem=nbelem; +#if TRACE_STRUCT +printf("EVOL 119 - tableau! %d elem(s)\n",nbelem); +#endif + ObjectArrayAddDynamicValueConcat((void **)&ae->rasmstructalias,&ae->irasmstructalias,&ae->mrasmstructalias,&rasmstructalias,sizeof(rasmstructalias)); + + /* create label for global struct ptr */ + curlabel.iw=-1; + curlabel.ptr=ae->codeadr; + curlabel.fileidx=ae->wl[ae->idx+2].ifile; + + if (!ae->getstruct) { + if (ae->wl[ae->idx+2].w[0]=='@') curlabel.name=MakeLocalLabel(ae,ae->wl[ae->idx+2].w,NULL); else curlabel.name=TxtStrDup(ae->wl[ae->idx+2].w); + curlabel.crc=GetCRC(curlabel.name); + PushLabelLight(ae,&curlabel); + } else { + /* or check for non-local name in struct declaration */ + if (ae->wl[ae->idx+2].w[0]=='@') { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"Meaningless use of local label in a STRUCT definition\n"); + } else { + curlabel.name=TxtStrDup(rasmstructalias.name); + curlabel.crc=GetCRC(curlabel.name); + PushLabelLight(ae,&curlabel); + } + } + + /* first field is in fact the very beginning of the structure */ + if (ae->getstruct) { + rasmstructfield.name=TxtStrDup(ae->wl[ae->idx+2].w); + rasmstructfield.offset=ae->codeadr; + ObjectArrayAddDynamicValueConcat((void **)&ae->rasmstruct[ae->irasmstruct-1].rasmstructfield, + &ae->rasmstruct[ae->irasmstruct-1].irasmstructfield,&ae->rasmstruct[ae->irasmstruct-1].mrasmstructfield, + &rasmstructfield,sizeof(rasmstructfield)); + } + + /* create subfields */ +#if TRACE_STRUCT +printf("create subfields\n"); +#endif + curlabel.iw=-1; + curlabel.ptr=ae->codeadr; + curlabel.ibank=ae->activebankactivebank:0; + for (i=0;irasmstruct[irs].irasmstructfield;i++) { + curlabel.ptr=ae->codeadr+ae->rasmstruct[irs].rasmstructfield[i].offset; + if (!ae->getstruct) { + curlabel.name=MemMalloc(strlen(ae->wl[ae->idx+2].w)+strlen(ae->rasmstruct[irs].rasmstructfield[i].name)+2); + sprintf(curlabel.name,"%s.%s",ae->wl[ae->idx+2].w,ae->rasmstruct[irs].rasmstructfield[i].name); + if (ae->wl[ae->idx+2].w[0]=='@') { + char *newlabel; + newlabel=MakeLocalLabel(ae,curlabel.name,NULL); + MemFree(curlabel.name); + curlabel.name=newlabel; + } + curlabel.crc=GetCRC(curlabel.name); + PushLabelLight(ae,&curlabel); + /* are we using a struct in a struct definition? */ + } else { + /* copy structname+label+offset in the structure */ + rasmstructfield.name=MemMalloc(strlen(ae->wl[ae->idx+2].w)+strlen(ae->rasmstruct[irs].rasmstructfield[i].name)+2); + sprintf(rasmstructfield.name,"%s.%s",ae->wl[ae->idx+2].w,ae->rasmstruct[irs].rasmstructfield[i].name); + rasmstructfield.offset=curlabel.ptr; + ObjectArrayAddDynamicValueConcat((void **)&ae->rasmstruct[ae->irasmstruct-1].rasmstructfield, + &ae->rasmstruct[ae->irasmstruct-1].irasmstructfield,&ae->rasmstruct[ae->irasmstruct-1].mrasmstructfield, + &rasmstructfield,sizeof(rasmstructfield)); + + /* need to push also generic label */ + curlabel.name=MemMalloc(strlen(ae->rasmstruct[ae->irasmstruct-1].name)+strlen(rasmstructfield.name)+2); /* overwrite PTR */ + sprintf(curlabel.name,"%s.%s",ae->rasmstruct[ae->irasmstruct-1].name,rasmstructfield.name); + curlabel.crc=GetCRC(curlabel.name); + PushLabelLight(ae,&curlabel); + } +#if TRACE_STRUCT +printf("pushLight [%s] %d:%X\n",curlabel.name,curlabel.ibank,curlabel.ptr); +#endif + } + + /* is there any filler in the declaration? */ + localsize=0; + + /* déterminer si on est en remplissage par défaut ou remplissage surchargé */ + + + + + +#if TRACE_STRUCT +printf("struct new behaviour (scan for %d fields)\n",ae->rasmstruct[irs].irasmstructfield); +#endif +#if 0 + for (i=0;irasmstruct[irs].irasmstructfield;i++) { + + if (!ae->wl[ae->idx+2+i].t || i+1>=ae->rasmstruct[irs].irasmstructfield) { + /* si le champ est sur le même offset que le précédent, on le saute */ + if (i && ae->rasmstruct[irs].rasmstructfield[i].offset>ae->rasmstruct[irs].rasmstructfield[i-1].offset) continue; + +#if TRACE_STRUCT +printf("get field? (%d)\n",irs); +#endif + if (!StringIsQuote(ae->wl[ae->idx+i].w)) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+i].w,1); + zeval=RoundComputeExpressionCore(ae,ae->wl[ae->idx+i].w,ae->codeadr,0); + } else { + // push string + } + + localsize+=ae->rasmstruct[irs].rasmstructfield[i].size; + + /* pour du single shot ? + pushbyte(s) at ae->codeadr+ae->rasmstruct[irs].rasmstructfield[i].offset + */ + + //ae->rasmstruct[irs].size; + + } else { +#if TRACE_STRUCT +printf("*break*\n"); +#endif + break; + } + } +#endif + + /* (LEGACY) filler, on balance des zéros */ +#if TRACE_STRUCT +printf("struct (almost) legacy filler from %d to %d-1\n",localsize,ae->rasmstruct[irs].size); +#endif + while (nbelem) { + for (i=cursize=0;irasmstruct[irs].irasmstructfield && cursizerasmstruct[irs].rasmstructfield[i].size; + } + for (;irasmstruct[irs].irasmstructfield;i++) { + for (j=0;jrasmstruct[irs].rasmstructfield[i].idata;j++) { + ___output(ae,ae->rasmstruct[irs].rasmstructfield[i].data[j]); + } + } + nbelem--; + } + +#if 0 + for (i=localsize;irasmstruct[irs].size;i++) ___output(ae,0); +#endif + ae->idx+=2; // probablement à revoir dans le cas d'une init!!! + } + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"STRUCT directive needs one or two parameters\n"); + } +} +void __ENDSTRUCT(struct s_assenv *ae) { + #undef FUNC + #define FUNC "__ENDSTRUCT" + struct s_label curlabel={0}; + int i,newlen; +#if TRACE_STRUCT + printf("endstruct\n"); +#endif + + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ENDSTRUCT directive does not need parameter\n"); + } else { + if (ae->getstruct) { + ae->rasmstruct[ae->irasmstruct-1].size=ae->codeadr; + ae->getstruct=0; + + /* SIZEOF like Vasm with struct name */ + curlabel.name=TxtStrDup(ae->rasmstruct[ae->irasmstruct-1].name); + curlabel.crc=ae->rasmstruct[ae->irasmstruct-1].crc; + curlabel.iw=-1; + curlabel.ptr=ae->rasmstruct[ae->irasmstruct-1].size; + //curlabel.fileidx wont be used + PushLabelLight(ae,&curlabel); + + /* compute size for each field */ +#if TRACE_STRUCT + printf("compute field size\n"); +#endif + newlen=strlen(ae->rasmstruct[ae->irasmstruct-1].name)+2; + if (ae->rasmstruct[ae->irasmstruct-1].irasmstructfield) { + for (i=0;irasmstruct[ae->irasmstruct-1].irasmstructfield-1;i++) { + ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].size=ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i+1].offset-ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].offset; + ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].fullname=MemMalloc(newlen+strlen(ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].name)); + sprintf(ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].fullname,"%s.%s",ae->rasmstruct[ae->irasmstruct-1].name,ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].name); + ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].crc=GetCRC(ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].fullname); + } + ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].size=ae->rasmstruct[ae->irasmstruct-1].size-ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].offset; + ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].fullname=MemMalloc(newlen+strlen(ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].name)); + sprintf(ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].fullname,"%s.%s",ae->rasmstruct[ae->irasmstruct-1].name,ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].name); + ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].crc=GetCRC(ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].fullname); + } else { + rasm_printf(ae,KWARNING"[%s:%d] Warning: empty structure [%s]\n",GetCurrentFile(ae),ae->wl[ae->idx].l,curlabel.name); + if (ae->erronwarn) MaxError(ae); + } + + /* unwrap data capture */ +#if TRACE_STRUCT + printf("unwrap data capture\n"); +#endif + if (ae->as80==1 || ae->pasmo) {/* not for UZ80 */ + instruction[ICRC_DEFB].makemnemo=_DEFB_as80;instruction[ICRC_DB].makemnemo=_DEFB_as80; + instruction[ICRC_DEFW].makemnemo=_DEFW_as80;instruction[ICRC_DW].makemnemo=_DEFW_as80; + instruction[ICRC_DEFI].makemnemo=_DEFI_as80; + } else { + instruction[ICRC_DEFB].makemnemo=_DEFB;instruction[ICRC_DB].makemnemo=_DEFB; + instruction[ICRC_DEFW].makemnemo=_DEFW;instruction[ICRC_DW].makemnemo=_DEFW; + instruction[ICRC_DEFI].makemnemo=_DEFI; + } + instruction[ICRC_DEFF].makemnemo=_DEFF;instruction[ICRC_DF].makemnemo=_DEFF; + instruction[ICRC_DEFR].makemnemo=_DEFR;instruction[ICRC_DR].makemnemo=_DEFR; + instruction[ICRC_DEFS].makemnemo=_DEFS;instruction[ICRC_DS].makemnemo=_DEFS; + + /* like there was no byte */ + ae->outputadr=ae->backup_outputadr; + ae->codeadr=ae->backup_codeadr; + + ___org_close(ae); + ___org_new(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ENDSTRUCT encountered outside STRUCT declaration\n"); + } + } +} + +void __MEMSPACE(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___new_memory_space(ae); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"MEMSPACE directive does not need parameter\n"); + } +} + +int (*_internal_getsample)(unsigned char *data, int *idx); +#undef FUNC +#define FUNC "_internal_AudioGetSampleValue" + +int __internal_getsample8(unsigned char *data, int *idx) { + int v; + v=data[*idx]-128;*idx=*idx+1;return v; +} +int __internal_getsample16little(unsigned char *data, int *idx) { + int cursample; + char *sdata=(char *)data; + cursample=sdata[*idx+1];*idx=*idx+2; + return cursample; +} +int __internal_getsample24little(unsigned char *data, int *idx) { + int cursample; + char *sdata=(char *)data; + cursample=sdata[*idx+2];*idx=*idx+3; + return cursample; +} +/* big-endian */ +int __internal_getsample16big(unsigned char *data, int *idx) { + int cursample; + char *sdata=(char *)data; + cursample=sdata[*idx];*idx=*idx+2; + return cursample; +} +int __internal_getsample24big(unsigned char *data, int *idx) { + int cursample; + char *sdata=(char *)data; + cursample=sdata[*idx];*idx=*idx+3; + return cursample; +} +/* float & endian shit */ +int _isLittleEndian() /* from lz4.h */ +{ +#ifdef NO_3RD_PARTIES + #if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) + typedef uint32_t U32; + #else + typedef unsigned int U32; + #endif +#endif + const union { U32 u; unsigned char c[4]; } one = { 1 }; + return one.c[0]; +} + +unsigned char * __internal_floatinversion(unsigned char *data) { + static unsigned char bswap[4]; + bswap[0]=data[3]; + bswap[1]=data[2]; + bswap[2]=data[1]; + bswap[3]=data[0]; + return bswap; +} + +int __internal_getsample32bigbig(unsigned char *data, int *idx) { + float fsample; + int cursample; + fsample=*((float*)(data+*idx)); + *idx=*idx+4; + cursample=(floor)((fsample+1.0)*127.5+0.5); + return cursample; +} +int __internal_getsample32biglittle(unsigned char *data, int *idx) { + float fsample; + int cursample; + fsample=*((float*)(__internal_floatinversion(data+*idx))); + *idx=*idx+4; + cursample=(floor)((fsample+1.0)*127.5+0.5); + return cursample; +} + +#define __internal_getsample32littlelittle __internal_getsample32bigbig +#define __internal_getsample32littlebig __internal_getsample32biglittle + + +void _AudioLoadSample(struct s_assenv *ae, unsigned char *data, unsigned int filesize, enum e_audio_sample_type sample_type, float normalize) +{ + #undef FUNC + #define FUNC "AudioLoadSample" + + struct s_wav_header *wav_header; + int i,j,n,idx,controlsize; + int nbchannel,bitspersample,nbsample; + int bigendian=0,cursample,wFormat; + double frequency; + double accumulator; + unsigned char samplevalue=0, sampleprevious=0; + int samplerepeat=0,ipause,mypsgreg; + + unsigned char *subchunk; + int subchunksize; + + if (filesizewl[ae->idx].l,"WAV import - this file is too small to be a valid WAV!\n"); + return; + } + + wav_header=(struct s_wav_header *)data; + +#if TRACE_HEXBIN +printf("AudioLoadSample filesize=%d st=%d normalize=%.2lf\n",filesize,sample_type,normalize); +#endif + if (strncmp(wav_header->ChunkID,"RIFF",4)) { + if (strncmp(wav_header->ChunkID,"RIFX",4)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WAV import - unsupported audio sample type (chunkid must be 'RIFF' or 'RIFX')\n"); + return; + } else { + bigendian=1; + } + } + if (strncmp(wav_header->Format,"WAVE",4)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"[%s:%d] WAV import - unsupported audio sample type (format must be 'WAVE')\n"); + return; + } + controlsize=wav_header->SubChunk1Size[0]+wav_header->SubChunk1Size[1]*256+wav_header->SubChunk1Size[2]*65536+wav_header->SubChunk1Size[3]*256*65536; + if (controlsize!=16) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WAV import - invalid wav chunk size (subchunk1 control)\n"); + return; + } + if (strncmp(wav_header->SubChunk1ID,"fmt",3)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WAV import - unsupported audio sample type (subchunk1id must be 'fmt')\n"); + return; + } + +#if TRACE_HEXBIN +printf("AudioLoadSample getsubchunk\n"); +#endif + subchunk=(unsigned char *)&wav_header->SubChunk2ID; + while (strncmp((char *)subchunk,"data",4)) { + subchunksize=8+subchunk[4]+subchunk[5]*256+subchunk[6]*65536+subchunk[7]*256*65536; + if (subchunksize>=filesize) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WAV import - data subchunk not found\n"); + return; + } + subchunk+=subchunksize; + } + subchunksize=subchunk[4]+subchunk[5]*256+subchunk[6]*65536+subchunk[7]*256*65536; + controlsize=subchunksize; + + nbchannel=wav_header->NumChannels[0]+wav_header->NumChannels[1]*256; + if (nbchannel<1) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WAV import - invalid number of audio channel\n"); + return; + } + + wFormat=wav_header->AudioFormat[0]+wav_header->AudioFormat[1]*256; + if (wFormat!=1 && wFormat!=3) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WAV import - invalid or unsupported wFormatTag (%04X)\n",wFormat); + return; + } + + frequency=wav_header->SampleRate[0]+wav_header->SampleRate[1]*256+wav_header->SampleRate[2]*65536+wav_header->SampleRate[3]*256*65536; + switch (sample_type) { + case AUDIOSAMPLE_DMAA: + case AUDIOSAMPLE_DMAB: + case AUDIOSAMPLE_DMAC: + if (fabs(frequency/15125.0-1.0)>0.2) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: WAV sample frequency (%dHz) is very different from 15KHz DMA frequency\n",GetCurrentFile(ae),ae->wl[ae->idx].l,(int)frequency); + if (ae->erronwarn) MaxError(ae); + } + } + default:break; + } + + bitspersample=wav_header->BitsPerSample[0]+wav_header->BitsPerSample[1]*256; +#if TRACE_HEXBIN +printf("AudioLoadSample bitpersample=%d | Format=%s\n",bitspersample,wFormat==1?"PCM":"IEEE Float"); +#endif + switch (bitspersample) { + case 8:_internal_getsample=__internal_getsample8;break; + case 16:if (!bigendian) _internal_getsample=__internal_getsample16little; else _internal_getsample=__internal_getsample16big;break; + case 24:if (!bigendian) _internal_getsample=__internal_getsample24little; else _internal_getsample=__internal_getsample24big;break; + case 32:if (wFormat==3) { + if (!bigendian) { + if (_isLittleEndian()) { + _internal_getsample=__internal_getsample32littlelittle; + } else { + _internal_getsample=__internal_getsample32littlebig; + } + } else { + if (_isLittleEndian()) { + _internal_getsample=__internal_getsample32biglittle; + } else { + _internal_getsample=__internal_getsample32bigbig; + } + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WAV import - unsupported 32bits PCM\n",wFormat); + return; + } + break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WAV import - unsupported bits per sample (%d)\n",bitspersample); + return; + } + + nbsample=controlsize/nbchannel/(bitspersample/8); + if (controlsize+sizeof(struct s_wav_header)>filesize) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WAV import - cannot read %d byte%s of audio whereas the file is %d bytes big!\n",controlsize,controlsize>1?"s":"",filesize); + return; + } + +#if TRACE_HEXBIN +printf("nbsample=%d (sze=%d,chn=%d,bps=%d) st=%d\n",nbsample,controlsize,nbchannel,bitspersample,sample_type); +#endif + + idx=subchunk-data; + switch (sample_type) { + default: + case AUDIOSAMPLE_SMP: + for (i=0;ipsgfine[cursample]; + + /* output */ + ___output(ae,samplevalue); + } + break; + case AUDIOSAMPLE_SM2: + /* +1 pour éviter le segfault */ + for (i=0;ipsgfine[cursample]); + } + + /* output */ + ___output(ae,samplevalue); + } + break; + case AUDIOSAMPLE_SM4: + /*** + SM4 format has two bits + bits -> PSG value + 00 -> 0 + 01 -> 13 + 10 -> 14 + 11 -> 15 + ***/ + /* +3 pour éviter le segfault */ + for (i=0;ipsgtab[cursample]>>2); + } + /* output */ + ___output(ae,samplevalue); + } + break; + case AUDIOSAMPLE_DMAA: + case AUDIOSAMPLE_DMAB: + case AUDIOSAMPLE_DMAC: + switch (sample_type) { + case AUDIOSAMPLE_DMAA:mypsgreg=0x8;break; + case AUDIOSAMPLE_DMAB:mypsgreg=0x9;break; + case AUDIOSAMPLE_DMAC:mypsgreg=0xA;break; + default:printf("warning remover\n"); + } + /* downmixing */ + accumulator=0.0; + for (n=0;npsgtab[cursample]; + for (i=1;ipsgtab[cursample]; + + if (samplevalue==sampleprevious && i+1>8) &0xF)); /* pause */ + + samplerepeat-=4096; + if (samplerepeat<0) samplerepeat=0; + } + } + sampleprevious=samplevalue; + } + } + /* if last sample is alone */ + if (!samplerepeat) { + ___output(ae,sampleprevious); + ___output(ae,mypsgreg); /* volume canal A/B/C */ + } + break; + } +} + + +#ifdef NOAPULTRA + int LZSA_crunch(unsigned char *input_data,int input_size,unsigned char **lzdata,int *lzlen) { + lzdata=MemMalloc(4); + *lzlen=0; + +printf("no LZSA support in this version!\n"); +fprintf(stderr,"no LZSA support in this version!\n"); + + return 0; + } + int APULTRA_crunch(unsigned char *input_data,int input_size,unsigned char **lzdata,int *lzlen) { + lzdata=MemMalloc(4); + *lzlen=0; + +printf("no AP-Ultra support in this version!\n"); +fprintf(stderr,"no AP-Ultra support in this version!\n"); + + return 0; + } +#endif + +/* + meta fonction qui gère le INCBIN standard plus les variantes SMP et DMA +*/ +void __READ(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + int idx; + + idx=atoi(ae->wl[ae->idx+1].w); + ae->idx++; + + if (idx>=0 && idxih) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"File to include was not found [%s]\n",ae->hexbin[idx].filename); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"internal error with text file import (index out of bounds)\n"); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"READ directive need a proper filename as argument\n"); + } +} + +void __HEXBIN(struct s_assenv *ae) { + #undef FUNC + #define FUNC "__HEXBIN" + + int hbinidx,overwritecheck=1,crc; + struct s_expr_dico *rvar; + unsigned int idx; + int size=0,offset=0; + float amplification=1.0; + int deload=0; + int vtiles=0,remap=0,revert=0; + int itiles=0,tilex=0,gtiles=0; + struct s_hexbin *curhexbin; + unsigned char *newdata=NULL; + int fileok=0,incwav=0; + + if (!ae->wl[ae->idx].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,1); + hbinidx=RoundComputeExpressionCore(ae,ae->wl[ae->idx+1].w,ae->codeadr,0); + if (hbinidx>=ae->ih) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"internal error with binary file import (index out of bounds)\n"); + return; + } +#if TRACE_HEXBIN +printf("Hexbin idx=[%s] filename=[%s]\n",ae->wl[ae->idx+1].w,ae->hexbin[hbinidx].filename); +#endif + + if (!ae->wl[ae->idx+1].t) { + if (strcmp("DSK",ae->wl[ae->idx+2].w)==0) { + /* import binary from DSK */ + } else if (strchr("SD",ae->wl[ae->idx+2].w[0]) && ae->wl[ae->idx+2].w[1]=='M' && strchr("P24A",ae->wl[ae->idx+2].w[2]) && !ae->wl[ae->idx+2].w[3]) { + /* SMP,SM2,SM4,DMA */ +#if TRACE_HEXBIN +printf("Hexbin for WAV-> %s (no operation until delayed load)\n",ae->wl[ae->idx+2].w); +#endif + incwav=1; + } else { + /* legacy binary file */ +#if TRACE_HEXBIN +printf("Hexbin legacy datalen=%d\n",ae->hexbin[hbinidx].datalen); +#endif + if (strcmp("REVERT",ae->wl[ae->idx+2].w)==0) { + /* revert data */ + if (!ae->wl[ae->idx+2].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN REVERT does not need extra parameters\n"); + } +#if TRACE_HEXBIN +printf(" -> REVERT loading\n"); +#endif + revert=1; + offset=size=0; // full file + ae->idx++; + + } else if (strcmp("REMAP",ae->wl[ae->idx+2].w)==0) { + /* reorder tiles data */ + if (!ae->wl[ae->idx+2].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+3].w,1); + remap=RoundComputeExpressionCore(ae,ae->wl[ae->idx+3].w,ae->codeadr,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN REMAP need a number of columns for reordering\n"); + } +#if TRACE_HEXBIN +printf(" -> REMAP loading\n"); +#endif + offset=size=0; // full file + ae->idx+=2; + + } else if (strcmp("GTILES",ae->wl[ae->idx+2].w)==0) { + /*** entrelace les tiles, besoin de hauteur et largeur de la tile ***/ + if (!ae->wl[ae->idx+2].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+3].w,1); + tilex=RoundComputeExpressionCore(ae,ae->wl[ae->idx+3].w,ae->codeadr,0); + gtiles=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"usage is INCBIN'file',GTILES,width\n"); + tilex=0; + } +#if TRACE_HEXBIN +printf(" -> GTILES loading\n"); +#endif + offset=size=0; // full file + ae->idx+=2; + } else if (strcmp("ITILES",ae->wl[ae->idx+2].w)==0) { + /*** entrelace les tiles, besoin de hauteur et largeur de la tile ***/ + if (!ae->wl[ae->idx+2].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+3].w,1); + tilex=RoundComputeExpressionCore(ae,ae->wl[ae->idx+3].w,ae->codeadr,0); + itiles=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"usage is INCBIN'file',ITILES,width\n"); + tilex=0; + } +#if TRACE_HEXBIN +printf(" -> ITILES loading\n"); +#endif + offset=size=0; // full file + ae->idx+=2; + } else if (strcmp("VTILES",ae->wl[ae->idx+2].w)==0) { + /* import and reorder tiles */ + if (!ae->wl[ae->idx+2].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+3].w,1); + vtiles=RoundComputeExpressionCore(ae,ae->wl[ae->idx+3].w,ae->codeadr,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN VTILES need a number of lines for reordering\n"); + } +#if TRACE_HEXBIN +printf(" -> VTILES loading\n"); +#endif + offset=size=0; // full file + ae->idx+=2; + } else { + char *expwrk; + + expwrk=TxtStrDup(ae->wl[ae->idx+2].w); + ExpressionFastTranslate(ae,&expwrk,1); + offset=RoundComputeExpressionCore(ae,expwrk,ae->codeadr,0); + MemFree(expwrk); +#if TRACE_HEXBIN + printf("offset=%d\n",offset); +#endif + if (!ae->wl[ae->idx+2].t) { + if (ae->wl[ae->idx+3].w[0]) { + expwrk=TxtStrDup(ae->wl[ae->idx+3].w); + ExpressionFastTranslate(ae,&expwrk,1); + size=RoundComputeExpressionCore(ae,expwrk,ae->codeadr,0); + MemFree(expwrk); + } else { + size=0; + } +#if TRACE_HEXBIN + printf("size=%d\n",size); +#endif + if (size<-65535 || size>65536) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN invalid size\n"); + } + if (!ae->wl[ae->idx+3].t) { + if (ae->wl[ae->idx+4].w[0]) { + expwrk=TxtStrDup(ae->wl[ae->idx+4].w); + ExpressionFastTranslate(ae,&expwrk,1); + offset+=65536*RoundComputeExpressionCore(ae,expwrk,ae->codeadr,0); + MemFree(expwrk); + } + if (!ae->wl[ae->idx+4].t) { + if (strcmp(ae->wl[ae->idx+5].w,"OFF")==0) { + overwritecheck=0; + } else if (strcmp(ae->wl[ae->idx+5].w,"ON")==0) { + overwritecheck=1; +#if TRACE_HEXBIN + printf("mode OVERWRITE\n"); +#endif + } else if (ae->wl[ae->idx+5].w[0]) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN invalid overwrite value. Must be 'OFF' or 'ON'\n"); + } + if (!ae->wl[ae->idx+5].t) { + /* copy raw len to a (new) variable */ + crc=GetCRC(ae->wl[ae->idx+6].w); + if ((rvar=SearchDico(ae,ae->wl[ae->idx+6].w,crc))!=NULL) { + rvar->v=ae->hexbin[hbinidx].rawlen; + } else { + /* mais ne peut être un label ou un alias */ + ExpressionSetDicoVar(ae,ae->wl[ae->idx+6].w,ae->hexbin[hbinidx].rawlen,0); + } + ae->idx+=6; + } else { + ae->idx+=5; + } + } else { + ae->idx+=4; + } + } else { + ae->idx+=3; + } + } else { + ae->idx+=2; + } + } + } + } else { + ae->idx++; + } + + curhexbin=&ae->hexbin[hbinidx]; + + /* preprocessor cannot manage variables so here is the delayed load */ + if (ae->hexbin[hbinidx].datalen<0) { + char *newfilename; + int lm,touched; + +#if TRACE_HEXBIN +printf("Hexbin -> as only the assembler know how to deal with var,\n"); +printf("we look for tags in the name of a file which were not found\n"); +#endif + + newfilename=TxtStrDup(curhexbin->filename); + + /* need to upper case tags */ + for (lm=touched=0;newfilename[lm];lm++) { + if (newfilename[lm]=='{') touched++; else if (newfilename[lm]=='}') touched--; else if (touched) newfilename[lm]=toupper(newfilename[lm]); + } + /* on essaie d'interpréter le nom du fichier en dynamique */ + newfilename=TranslateTag(ae,newfilename,&touched,1,E_TAGOPTION_REMOVESPACE); + + /* Where is the file to load? */ + if (!FileExists(newfilename)) { + int ilookfile; + char *filename_toread; + + /* on cherche dans les include */ + for (ilookfile=0;ilookfileipath && !fileok;ilookfile++) { + filename_toread=MergePath(ae,ae->includepath[ilookfile],newfilename); + if (FileExists(filename_toread)) { + fileok=1; + MemFree(newfilename); + newfilename=TxtStrDup(filename_toread); // Merge renvoie un static + } + } + } else { + fileok=1; + } + + if (fileok) { +#if TRACE_HEXBIN +printf("Hexbin -> surprise! we found the file!\n"); +#endif + curhexbin->rawlen=curhexbin->datalen=FileGetSize(newfilename); + curhexbin->data=MemMalloc(curhexbin->datalen*1.3+10); + if (FileReadBinary(newfilename,(char*)curhexbin->data,curhexbin->datalen)!=curhexbin->datalen) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"read error on file [%s]\n",newfilename); + MemFree(curhexbin->data); + MemFree(newfilename); + return; + } + FileReadBinaryClose(newfilename); + deload=1; + } else { + /* still not found */ + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"file not found [%s]\n",newfilename); + MemFree(newfilename); + return; + } + MemFree(newfilename); + } + + if (incwav) { + /* SMP,SM2,SM4,DMA */ + int dma_args=3; + int dma_channel=AUDIOSAMPLE_DMAC; + int dma_int=0,dma_repeat=0; + int mypsgreg=0xA; +#if TRACE_HEXBIN +printf("Hexbin -> %s\n",ae->wl[ae->idx+2].w); +#endif + switch (ae->wl[ae->idx+2].w[2]) { + case 'P':case '2':case '4': + if (!ae->wl[ae->idx+2].t) { + amplification=ComputeExpressionCore(ae,ae->wl[ae->idx+3].w,ae->codeadr,0); +#if TRACE_HEXBIN + printf("sample amplification=%.2lf\n",amplification); +#endif + } + default:break; + } + + switch (ae->wl[ae->idx+2].w[2]) { + case 'P':_AudioLoadSample(ae,ae->hexbin[hbinidx].data,ae->hexbin[hbinidx].datalen, AUDIOSAMPLE_SMP,amplification);break; + case '2':_AudioLoadSample(ae,ae->hexbin[hbinidx].data,ae->hexbin[hbinidx].datalen, AUDIOSAMPLE_SM2,amplification);break; + case '4':_AudioLoadSample(ae,ae->hexbin[hbinidx].data,ae->hexbin[hbinidx].datalen, AUDIOSAMPLE_SM4,amplification);break; + case 'A':/* DMA options */ + if (!ae->wl[ae->idx+2].t) { + while (!ae->wl[ae->idx+dma_args].t) { + dma_args++; + if (strcmp(ae->wl[ae->idx+dma_args].w,"DMA_INT")==0) { + dma_int=1; + } else if (strcmp(ae->wl[ae->idx+dma_args].w,"DMA_REPEAT")==0) { + if (!ae->wl[ae->idx+dma_args].t) { + dma_args++; + dma_repeat=ComputeExpressionCore(ae,ae->wl[ae->idx+dma_args].w,ae->codeadr,0); + if (dma_repeat<1 || dma_repeat>4095) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DMA_REPEAT value out of bounds (1-4095)\n"); + dma_repeat=0; + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DMA_REPEAT must be followed by another parameter\n"); + } + } else if (strcmp(ae->wl[ae->idx+dma_args].w,"DMA_CHANNEL_A")==0) { + dma_channel=AUDIOSAMPLE_DMAA; + mypsgreg=0x8; + } else if (strcmp(ae->wl[ae->idx+dma_args].w,"DMA_CHANNEL_B")==0) { + dma_channel=AUDIOSAMPLE_DMAB; + mypsgreg=0x9; + } else if (strcmp(ae->wl[ae->idx+dma_args].w,"DMA_CHANNEL_C")==0) { + dma_channel=AUDIOSAMPLE_DMAC; + mypsgreg=0xA; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Unrecognized DMA option [%s]\n",ae->wl[ae->idx+dma_args].w); + } + } + } + if (dma_repeat) { + ___output(ae,dma_repeat&0xFF); + ___output(ae,0x20|((dma_repeat>>8)&0xF)); + } + _AudioLoadSample(ae,ae->hexbin[hbinidx].data,ae->hexbin[hbinidx].datalen, dma_channel,amplification); + if (dma_repeat) { + ___output(ae,0x01); + ___output(ae,0x40); /* LOOP */ + } + ___output(ae,0); + ___output(ae,mypsgreg); /* volume to zero */ + if (dma_int) { + ___output(ae,0x10); + ___output(ae,0x40); /* INT */ + } + ___output(ae,0x20); + ___output(ae,0x40); /* Mandatory STOP */ + break; + + default:printf("warning remover\n");break; + } + ae->idx+=2; + return; + } + + if (ae->hexbin[hbinidx].datalen>0) { + if (hbinidxih && hbinidx>=0) { + /* pre-parametres OK (longueur+IDX struct) */ + if (size<0) { +#if TRACE_HEXBIN +printf("taille négative %d -> conversion en %d\n",size,ae->hexbin[hbinidx].datalen+size); +#endif + size=ae->hexbin[hbinidx].datalen+size; + if (size<1) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN negative size is greater or equal to filesize\n"); + } + } + /* negative offset conversion */ + if (offset<0) { +#if TRACE_HEXBIN +printf("offset négatif %d -> conversion en %d\n",offset,ae->hexbin[hbinidx].datalen+offset); +#endif + offset=ae->hexbin[hbinidx].datalen+offset; + } + if (!size) { + if (!offset) { + size=ae->hexbin[hbinidx].datalen; + } else { + size=ae->hexbin[hbinidx].datalen-offset; + } +#if TRACE_HEXBIN +printf("taille nulle et offset=%d -> conversion en %d\n",offset,size); +#endif + } + if (size>ae->hexbin[hbinidx].datalen) { + rasm_printf(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN size is greater than filesize\n"); + } else { + if (size+offset>ae->hexbin[hbinidx].datalen) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN size+offset is greater than filesize\n"); + } else { + /* OUTPUT DATA */ + unsigned char *outputdata; + int outputidx=0; + outputdata=MemMalloc(ae->hexbin[hbinidx].datalen); +#if TRACE_HEXBIN +printf("output fictif pour réorganiser les données\n"); +#endif + + if (revert) { + int p; + p=size-1; + while (p>=0) { + outputdata[outputidx++]=ae->hexbin[hbinidx].data[p--]; + } + } else if (itiles || gtiles) { + /* tiles data reordering */ + int tx,it; + + if (size % (tilex*8)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN ITILES/GTILES cannot reorder tiles %d bytewidth with file of size %d\n",tilex,size); + } else { + if (itiles) { + /* zigzag with regular gray coding */ + it=0; + while (ithexbin[hbinidx].data[it+tx+0*tilex]; + for (tx=tilex-1;tx>=0;tx--) outputdata[outputidx++]=ae->hexbin[hbinidx].data[it+tx+1*tilex]; + for (tx=0;txhexbin[hbinidx].data[it+tx+3*tilex]; + for (tx=tilex-1;tx>=0;tx--) outputdata[outputidx++]=ae->hexbin[hbinidx].data[it+tx+2*tilex]; + for (tx=0;txhexbin[hbinidx].data[it+tx+6*tilex]; + for (tx=tilex-1;tx>=0;tx--) outputdata[outputidx++]=ae->hexbin[hbinidx].data[it+tx+7*tilex]; + for (tx=0;txhexbin[hbinidx].data[it+tx+5*tilex]; + for (tx=tilex-1;tx>=0;tx--) outputdata[outputidx++]=ae->hexbin[hbinidx].data[it+tx+4*tilex]; + it+=tilex*8; + } + } else { + /* only reorder lines with regular gray coding */ + it=0; + while (ithexbin[hbinidx].data[it+tx+0*tilex]; + for (tx=0;txhexbin[hbinidx].data[it+tx+1*tilex]; + for (tx=0;txhexbin[hbinidx].data[it+tx+3*tilex]; + for (tx=0;txhexbin[hbinidx].data[it+tx+2*tilex]; + for (tx=0;txhexbin[hbinidx].data[it+tx+6*tilex]; + for (tx=0;txhexbin[hbinidx].data[it+tx+7*tilex]; + for (tx=0;txhexbin[hbinidx].data[it+tx+5*tilex]; + for (tx=0;txhexbin[hbinidx].data[it+tx+4*tilex]; + it+=tilex*8; + } + } + } + } else if (remap) { + /* tiles data reordering */ + int tx,it,width; + + width=size/remap; + + if ((size % remap) || (remap*width>size)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN REMAP cannot reorder %d columns%s with file of size %d\n",remap,remap>1?"s":"",size); + } else { + for (it=0;ithexbin[hbinidx].data[it+tx*remap]; + } + } + } + + } else if (vtiles) { + /* tiles map reordering */ + int width,tilex,tiley; + + width=size/vtiles; + + if ((size % vtiles) || (vtiles*width>size)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN VTILES cannot reorder %d line%s with file of size %d\n",vtiles,vtiles>1?"s":"",size); + } else { +#if TRACE_HEXBIN +printf("Hexbin -> re-tiling MAP! width=%d\n",width); +#endif + for (idx=tilex=tiley=0;idxhexbin[hbinidx].data[tilex+tiley*width]; + tiley++; + if (tiley>=vtiles) { + tiley=0; + tilex++; + } + } + } + } else { +#if TRACE_HEXBIN +printf("Hexbin -> Legacy output from %d to %d\n",offset,size+offset); +if (curhexbin->crunch) printf("CRUNCHED! (%d)\n",curhexbin->crunch); +#endif + /* only from offset to size+offset */ + for (idx=offset;idxhexbin[hbinidx].data[idx]; + } + + switch (curhexbin->crunch) { + #ifndef NO_3RD_PARTIES + case 4: + newdata=LZ4_crunch(outputdata,outputidx,&outputidx); + MemFree(outputdata); + outputdata=newdata; + #if TRACE_PREPRO + rasm_printf(ae,KVERBOSE"crunched with LZ4 into %d byte(s)\n",outputidx); + #endif + break; + + case 70: + { + int delta,slzlen; + + if (outputidx>=1024 && MAX_OFFSET_ZX0>5000) rasm_printf(ae,KWARNING"ZX0 is crunching %.1fkb this may take a while, be patient...\n",outputidx/1024.0); + newdata=zx0_compress(zx0_optimize(outputdata, outputidx, 0, MAX_OFFSET_ZX0), outputdata, outputidx, 0, 0, 1, &slzlen, &delta); + outputidx=slzlen; + MemFree(outputdata); + outputdata=newdata; + #if TRACE_PREPRO + rasm_printf(ae,KVERBOSE"crunched with ZX0 into %d byte(s) delta=%d\n",outputidx,delta); + #endif + } + break; + case 71: + { + int delta,slzlen; + + if (outputidx>=1024 && MAX_OFFSET_ZX0>5000) rasm_printf(ae,KWARNING"ZX0 is crunching %.1fkb this may take a while, be patient...\n",outputidx/1024.0); + zx0_reverse(outputdata,outputdata+outputidx-1); + newdata=zx0_compress(zx0_optimize(outputdata, outputidx, 0, MAX_OFFSET_ZX0), outputdata, outputidx, 0, 1, 0,&slzlen, &delta); + zx0_reverse(newdata,newdata+slzlen-1); + outputidx=slzlen; + MemFree(outputdata); + outputdata=newdata; + #if TRACE_PREPRO + rasm_printf(ae,KVERBOSE"crunched with ZX0 backward into %d byte(s) delta=%d\n",outputidx,delta); + #endif + } + break; + case 7: + { + int slzlen; + newdata=ZX7_compress(zx7_optimize(outputdata, outputidx), outputdata, outputidx, &slzlen); + outputidx=slzlen; + MemFree(outputdata); + outputdata=newdata; + #if TRACE_PREPRO + rasm_printf(ae,KVERBOSE"crunched with ZX7 into %d byte(s)\n",outputidx); + #endif + } + break; + case 8: + if (outputidx>=1024) rasm_printf(ae,KWARNING"Exomizer is crunching %.1fkb this may take a while, be patient...\n",outputidx/1024.0); + newdata=Exomizer_crunch(outputdata,outputidx,&outputidx); + MemFree(outputdata); + outputdata=newdata; + #if TRACE_PREPRO + rasm_printf(ae,KVERBOSE"crunched with Exomizer into %d byte(s)\n",outputidx); + #endif + break; + case 17: + if (outputidx>=1024) rasm_printf(ae,KWARNING"AP-Ultra is crunching %.1fkb this may take a while, be patient...\n",outputidx/1024.0); + { + int nnewlen; + APULTRA_crunch(outputdata,outputidx,&newdata,&nnewlen); + outputidx=nnewlen; + } + MemFree(outputdata); + outputdata=newdata; + #if TRACE_PREPRO + rasm_printf(ae,KVERBOSE"crunched with AP-Ultra into %d byte(s)\n",outputidx); + #endif + break; + case 18: + if (outputidx>=16384 && curhexbin->version==2) rasm_printf(ae,KWARNING"LZSA2 is crunching %.1fkb this may take a while, be patient...\n",outputidx/1024.0); + { + int nnewlen; + LZSA_crunch(outputdata,outputidx,&newdata,&nnewlen,curhexbin->version,curhexbin->minmatch); + outputidx=nnewlen; + } + MemFree(outputdata); + outputdata=newdata; + #if TRACE_PREPRO + rasm_printf(ae,KVERBOSE"crunched with LZSA%d into %d byte(s)\n",curhexbin->version,outputidx); + #endif + break; + #endif + case 48: + newdata=LZ48_crunch(outputdata,outputidx,&outputidx); + MemFree(outputdata); + outputdata=newdata; + #if TRACE_PREPRO + rasm_printf(ae,KVERBOSE"crunched with LZ48 into %d byte(s)\n",outputidx); + #endif + break; + case 49: + newdata=LZ49_crunch(outputdata,outputidx,&outputidx); + MemFree(outputdata); + outputdata=newdata; + #if TRACE_PREPRO + rasm_printf(ae,KVERBOSE"crunched with LZ49 into %d byte(s)\n",outputidx); + #endif + break; + default:break; + } + + + if (!overwritecheck) { + rasm_printf(ae,KWARNING"INCBIN without overwrite check still not working...\n"); + if (ae->erronwarn) MaxError(ae); + } + } + + if (overwritecheck) { + for (idx=0;idxorgzone[ae->io-1].nocode=2; + ___org_close(ae); + ___org_new(ae,0); + } + + MemFree(outputdata); + } + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INTERNAL - HEXBIN refer to unknown structure\n"); + FreeAssenv(ae); + exit(2); + } + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INTERNAL - HEXBIN need one HEX parameter\n"); + FreeAssenv(ae); + exit(2); + } + + /* generated names must be reloaded! */ + if (deload) { + ae->hexbin[hbinidx].datalen=-1; + MemFree(ae->hexbin[hbinidx].data); + } +} + +/* +save "nom",start,size -> save binary +save "nom",start,size,TAPE,"cdtname" -> save tape file +save "nom",start,size,AMSDOS -> save binary with Amsdos header +save "nom",start,size,DSK,"dskname" -> save binary on DSK data format +save "nom",start,size,DSK,"dskname",B -> select face +save "nom",start,size,DSK,B -> current DSK, choose face +save "nom",start,size,DSK -> current DSK, current face +*/ +void __SAVE(struct s_assenv *ae) { + #undef FUNC + #define FUNC "__SAVE" + + struct s_save cursave={0}; + int ko=1,touched,lm; + char *filename; + + if (!ae->wl[ae->idx].t) { + /* nom de fichier entre quotes ou bien mot clef DSK */ + if (!StringIsQuote(ae->wl[ae->idx+1].w)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SAVE invalid filename quote\n"); + ko=0; + } else { + if (!ae->wl[ae->idx+1].t) { + filename=TxtStrDup(ae->wl[ae->idx+1].w); + /* need to upper case tags */ + for (lm=touched=0;filename[lm];lm++) { + if (filename[lm]=='{') touched++; else if (filename[lm]=='}') touched--; else if (touched) filename[lm]=toupper(filename[lm]); + } + filename=TranslateTag(ae,filename,&touched,1,E_TAGOPTION_REMOVESPACE); + if (!touched) MemFree(filename); + + if (!ae->wl[ae->idx+2].t && ae->wl[ae->idx+3].t!=2) { + cursave.ibank=ae->activebank; + cursave.ioffset=ae->idx+2; + ExpressionFastTranslate(ae,&ae->wl[ae->idx+2].w,1); // si on utilise des variables ça évite la grouille post traitement... + cursave.isize=ae->idx+3; + ExpressionFastTranslate(ae,&ae->wl[ae->idx+3].w,1); // idem + if (!touched) cursave.iw=ae->idx+1; else cursave.filename=filename; + cursave.irun=ae->current_run_idx; + if (!ae->wl[ae->idx+3].t) { + if (strcmp(ae->wl[ae->idx+4].w,"TAPE")==0) { + cursave.tape=1; + if (!ae->wl[ae->idx+4].t) { + cursave.iwdskname=ae->idx+5; + } else { + cursave.iwdskname=-1; + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"cannot autoselect TAPE, please specify a filename after TAPE arg\n"); + } + } else if (strcmp(ae->wl[ae->idx+4].w,"AMSDOS")==0) { + cursave.amsdos=1; + } else if (strcmp(ae->wl[ae->idx+4].w,"HOBETA")==0) { + cursave.hobeta=1; + } else if (strcmp(ae->wl[ae->idx+4].w,"DSK")==0) { +#if TRACE_EDSK + printf("DSK SAVE order [bnk: %d ioff: %d isiz: %d iw=%d [%s] [%s]\n",cursave.ibank,cursave.ioffset,cursave.isize,cursave.iw,ae->wl[ae->idx+2].w,ae->wl[ae->idx+3].w); +#endif + cursave.dsk=1; + if (!ae->wl[ae->idx+4].t) { + cursave.iwdskname=ae->idx+5; + if (!ae->wl[ae->idx+5].t) { + /* face selection - 0 as default */ + switch (ae->wl[ae->idx+6].w[0]) { + case '1': + case 'B': + cursave.face=1; + break; + case '0': + case 'A': + default: + cursave.face=0; + break; + } + } + } else { + if (ae->nbsave && ae->save[ae->nbsave-1].iwdskname!=-1) { + cursave.iwdskname=ae->save[ae->nbsave-1].iwdskname; /* previous DSK */ + cursave.face=ae->save[ae->nbsave-1].face; /* previous face */ + } else { + cursave.iwdskname=-1; + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"cannot autoselect DSK as there was not a previous selection\n"); + } + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SAVE 4th parameter must be empty or AMSDOS or DSK\n"); + ko=0; + } + } + ObjectArrayAddDynamicValueConcat((void**)&ae->save,&ae->nbsave,&ae->maxsave,&cursave,sizeof(cursave)); + ko=0; + } + } + } + } + if (ko) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use SAVE 'filename',offset,size[,AMSDOS|DSK[,A|B|'dskname'[,A|B]]]\n"); + } + while (!ae->wl[ae->idx].t) ae->idx++; +} + + +void __MODULE(struct s_assenv *ae) { + #undef FUNC + #define FUNC "__MODULE" + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + if (strcmp(ae->wl[ae->idx+1].w,"OFF")==0) { + if (ae->module || ae->modulen) MemFree(ae->module); + ae->module=NULL; + ae->modulen=0; + } else { + if (ae->modulen || ae->module) { + MemFree(ae->module); + } + ae->modulen=strlen(ae->wl[ae->idx+1].w); + ae->module=TxtStrDup(ae->wl[ae->idx+1].w); + } + ae->idx++; + } else { + if (ae->module || ae->modulen) MemFree(ae->module); + ae->module=NULL; + ae->modulen=0; + } +} +void __ENDMODULE(struct s_assenv *ae) { + #undef FUNC + #define FUNC "__ENDMODULE" + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ENDMODULE does not need any parameter\n"); + } else { + __MODULE(ae); + } +} + +void __SUMMEM(struct s_assenv *ae) { + struct s_poker poker={0}; + + if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + /* no poke in a NOCODE section */ + if (!ae->nocode) { + poker.method=E_POKER_SUM8; + poker.istart=ae->idx+1; + poker.iend=ae->idx+2; + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,1); + ExpressionFastTranslate(ae,&ae->wl[ae->idx+2].w,1); + poker.outputadr=ae->outputadr; + poker.ibank=ae->activebank; + poker.ipoker=ae->idx; + ObjectArrayAddDynamicValueConcat((void**)&ae->poker,&ae->nbpoker,&ae->maxpoker,&poker,sizeof(poker)); + } + ___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"usage is SUMMEM start,end\n"); + } +} + +void __XORMEM(struct s_assenv *ae) { + struct s_poker poker={0}; + + if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + /* no poke in a NOCODE section */ + if (!ae->nocode) { + poker.method=E_POKER_XOR8; + poker.istart=ae->idx+1; + poker.iend=ae->idx+2; + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,1); + ExpressionFastTranslate(ae,&ae->wl[ae->idx+2].w,1); + poker.outputadr=ae->outputadr; + poker.ibank=ae->activebank; + poker.ipoker=ae->idx; + ObjectArrayAddDynamicValueConcat((void**)&ae->poker,&ae->nbpoker,&ae->maxpoker,&poker,sizeof(poker)); + } + ___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"usage is XORMEM start,end\n"); + } +} + +void __CIPHERMEM(struct s_assenv *ae) { + struct s_poker poker={0}; + int ciphermode; + + if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t) { + /* cipher memory */ + if (!ae->nocode) { + if (!ae->wl[ae->idx+2].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+3].w,1); + ciphermode=RoundComputeExpression(ae,ae->wl[ae->idx+3].w,ae->outputadr,0,0); + switch (ciphermode) { + default: + case 0: + case 1:poker.method=E_POKER_CIPHER001;break; + case 2:poker.method=E_POKER_CIPHER002;break; + case 3:poker.method=E_POKER_CIPHER003; break; + case 4:poker.method=E_POKER_CIPHER004; + if (!ae->wl[ae->idx+3].t) { + poker.istring=ae->idx+4; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"usage is CIPHERMEM start,end,4,'keystring'\n"); + } + break; + } + switch (ciphermode) { + default: + case 0: + case 1: + case 2: + case 3: + if (!ae->wl[ae->idx+3].t) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: keystring parameter will be ignored\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + if (ae->erronwarn) MaxError(ae); + } + case 4: + break; + } + if (!ae->wl[ae->idx+3].t && !ae->wl[ae->idx+4].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Too many parameters! Usage is CIPHERMEM start,end[,method[,'keystring']]\n"); + } + } else { + poker.method=E_POKER_CIPHER001; + } + poker.istart=ae->idx+1; + poker.iend=ae->idx+2; + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,1); + ExpressionFastTranslate(ae,&ae->wl[ae->idx+2].w,1); + poker.outputadr=ae->outputadr; + poker.ibank=ae->activebank; + poker.ipoker=ae->idx; + ObjectArrayAddDynamicValueConcat((void**)&ae->poker,&ae->nbpoker,&ae->maxpoker,&poker,sizeof(poker)); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"usage is CIPHERMEM start,end[,method[,'keystring']]\n"); + } +} + +void __TIMESTAMP(struct s_assenv *ae) { + char Ltimestamp[32]; + char LTMP[64]; + struct tm *local; + char *timestr; + time_t now; + int idx=0; + int cpt; + + time(&now); + local=localtime(&now); + + if (!ae->wl[ae->idx].t) { + ae->idx++; + timestr=ae->wl[ae->idx].w+1; + } else { + timestr=Ltimestamp; + strcpy(timestr,"[Y-M-D h:m]"); + } + + while (timestr[idx]) { + switch (timestr[idx]) { + case 'Y': + cpt=0; + while (timestr[idx]=='Y') {idx++;cpt++;} + sprintf(LTMP,"%04d",local->tm_year+1900); + switch (cpt) { + case 2: //___output(ae,LTMP[2]); + ___output(ae,ae->charset[(unsigned int)LTMP[2]]); + ___output(ae,ae->charset[(unsigned int)LTMP[3]]); + break; + case 1: + case 4: //___output(ae,LTMP[0]); + ___output(ae,ae->charset[(unsigned int)LTMP[0]]); + ___output(ae,ae->charset[(unsigned int)LTMP[1]]); + ___output(ae,ae->charset[(unsigned int)LTMP[2]]); + ___output(ae,ae->charset[(unsigned int)LTMP[3]]); + break; + } + break; + case 'M': + while (timestr[idx]=='M') idx++; + sprintf(LTMP,"%02d",local->tm_mon+1); + ___output(ae,ae->charset[(unsigned int)LTMP[0]]); + ___output(ae,ae->charset[(unsigned int)LTMP[1]]); + break; + case 'D': + while (timestr[idx]=='D') idx++; + sprintf(LTMP,"%02d",local->tm_mday); + ___output(ae,ae->charset[(unsigned int)LTMP[0]]); + ___output(ae,ae->charset[(unsigned int)LTMP[1]]); + break; + case 'h': + while (timestr[idx]=='h') idx++; + sprintf(LTMP,"%02d",local->tm_hour); + ___output(ae,ae->charset[(unsigned int)LTMP[0]]); + ___output(ae,ae->charset[(unsigned int)LTMP[1]]); + break; + case 'm': + while (timestr[idx]=='m') idx++; + sprintf(LTMP,"%02d",local->tm_min); + ___output(ae,ae->charset[(unsigned int)LTMP[0]]); + ___output(ae,ae->charset[(unsigned int)LTMP[1]]); + break; + case 's': + while (timestr[idx]=='s') idx++; + sprintf(LTMP,"%02d",local->tm_sec); + ___output(ae,ae->charset[(unsigned int)LTMP[0]]); + ___output(ae,ae->charset[(unsigned int)LTMP[1]]); + break; + default: + if ((timestr[idx]=='\'' || timestr[idx]=='"') && !timestr[idx+1]) {} else ___output(ae,ae->charset[(unsigned int)timestr[idx]&0xFF]); + idx++; + break; + + } + } +} + +struct s_asm_keyword instruction[]={ +{"LD",0,_LD}, +{"DEC",0,_DEC}, +{"INC",0,_INC}, +{"ADD",0,_ADD}, +{"SUB",0,_SUB}, +{"OR",0,_OR}, +{"AND",0,_AND}, +{"XOR",0,_XOR}, +{"POP",0,_POP}, +{"PUSH",0,_PUSH}, +{"DJNZ",0,_DJNZ}, +{"JR",0,_JR}, +{"JP",0,_JP}, +{"CALL",0,_CALL}, +{"RET",0,_RET}, +{"EX",0,_EX}, +{"ADC",0,_ADC}, +{"SBC",0,_SBC}, +{"EXA",0,_EXA}, +{"EXX",0,_EXX}, +{"CP",0,_CP}, +{"BIT",0,_BIT}, +{"RES",0,_RES}, +{"SET",0,_SET}, +{"IN",0,_IN}, +{"OUT",0,_OUT}, +{"RLC",0,_RLC}, +{"RRC",0,_RRC}, +{"RL",0,_RL}, +{"RR",0,_RR}, +{"SLA",0,_SLA}, +{"SRA",0,_SRA}, +{"SLL",0,_SLL}, +{"SL1",0,_SLL}, +{"SRL",0,_SRL}, +{"RST",0,_RST}, +{"HALT",0,_HALT}, +{"DI",0,_DI}, +{"EI",0,_EI}, +{"NOP",0,_NOP}, +{"DEFF",0,_DEFF}, +{"DEFR",0,_DEFR}, +{"DEFB",0,_DEFB}, +{"DEFM",0,_DEFB}, +{"DF",0,_DEFF}, +{"DR",0,_DEFR}, +{"DM",0,_DEFB}, +{"DB",0,_DEFB}, +{"DEFW",0,_DEFW}, +{"DW",0,_DEFW}, +{"DEFS",0,_DEFS}, +{"DS",0,_DEFS}, +{"STR",0,_STR}, +{"LDI",0,_LDI}, +{"LDIR",0,_LDIR}, +{"OUTI",0,_OUTI}, +{"INI",0,_INI}, +{"RLCA",0,_RLCA}, +{"RRCA",0,_RRCA}, +{"NEG",0,_NEG}, +{"RLA",0,_RLA}, +{"RRA",0,_RRA}, +{"RLD",0,_RLD}, +{"RRD",0,_RRD}, +{"DAA",0,_DAA}, +{"CPL",0,_CPL}, +{"SCF",0,_SCF}, +{"LDD",0,_LDD}, +{"LDDR",0,_LDDR}, +{"CCF",0,_CCF}, +{"OUTD",0,_OUTD}, +{"IND",0,_IND}, +{"RETI",0,_RETI}, +{"RETN",0,_RETN}, +{"IM",0,_IM}, +{"DEFI",0,_DEFI}, +{"CPD",0,_CPD}, +{"CPI",0,_CPI}, +{"CPDR",0,_CPDR}, +{"CPIR",0,_CPIR}, +{"OTDR",0,_OTDR}, +{"OTIR",0,_OTIR}, +{"INDR",0,_INDR}, +{"INIR",0,_INIR}, +{"REPEAT",0,__REPEAT}, +{"STARTINGINDEX",0,__STARTINGINDEX}, +{"REND",0,__REND}, +{"ENDREPEAT",0,__REND}, +{"ENDREP",0,__REND}, +{"UNTIL",0,__UNTIL}, +{"ORG",0,__ORG}, +{"PROTECT",0,__PROTECT}, +{"WHILE",0,__WHILE}, +{"WEND",0,__WEND}, +{"READ",0,__READ}, +{"INCLUDE",0,__READ}, // anti-label +{"HEXBIN",0,__HEXBIN}, +{"ALIGN",0,__ALIGN}, +{"CONFINE",0,__CONFINE}, +{"ELSEIF",0,__ELSEIF}, +{"ELSE",0,__ELSE}, +{"IF",0,__IF}, +{"ENDIF",0,__ENDIF}, +{"IFNOT",0,__IFNOT}, +{"IFDEF",0,__IFDEF}, +{"IFNDEF",0,__IFNDEF}, +{"IFUSED",0,__IFUSED}, +{"IFNUSED",0,__IFNUSED}, +{"UNDEF",0,__UNDEF}, +{"CASE",0,__CASE}, +{"BREAK",0,__BREAK}, +{"DEFAULT",0,__DEFAULT}, +{"SWITCH",0,__SWITCH}, +{"ENDSWITCH",0,__ENDSWITCH}, +{"WRITE",0,__WRITE}, +{"CODE",0,__CODE}, +{"NOCODE",0,__NOCODE}, +{"MEMSPACE",0,__MEMSPACE}, +{"MACRO",0,__MACRO}, +{"TICKER",0,__TICKER}, +{"LET",0,__LET}, +{"ASSERT",0,__ASSERT}, +{"CHARSET",0,__CHARSET}, +{"RUN",0,__RUN}, +{"SAVE",0,__SAVE}, +{"BRK",0,__BRK}, +{"NOLIST",0,__NOLIST}, +{"LIST",0,__LIST}, +{"STOP",0,__STOP}, +{"PRINT",0,__PRINT}, +{"DELAYED_PRINT",0,__DELAYED_PRINT}, +{"FAIL",0,__FAIL}, +{"BREAKPOINT",0,__BREAKPOINT}, +{"BANK",0,__BANK}, +{"BANKSET",0,__BANKSET}, +{"NAMEBANK",0,__NameBANK}, +{"LIMIT",0,__LIMIT}, +{"LZEXO",0,__LZEXO}, +{"LZX7",0,__LZX7}, +{"LZX0",0,__LZX0}, +{"LZX0B",0,__LZX0B}, +{"LZAPU",0,__LZAPU}, +{"LZSA1",0,__LZSA1}, +{"LZSA2",0,__LZSA2}, +{"LZ4",0,__LZ4}, +{"LZ48",0,__LZ48}, +{"LZ49",0,__LZ49}, +{"LZCLOSE",0,__LZCLOSE}, +{"SNASET",0,__SNASET}, +{"SNAPINIT",0,__SNAPINIT}, +{"BUILDZX",0,__BUILDZX}, +{"BUILDOBJ",0,__BUILDOBJ}, +{"BUILDCPR",0,__BUILDCPR}, +{"BUILDSNA",0,__BUILDSNA}, +{"BUILDROM",0,__BUILDROM}, +{"BUILDTAPE",0,__BUILDTAPE}, +{"SETCPC",0,__SETCPC}, +{"SETCRTC",0,__SETCRTC}, +{"AMSDOS",0,__AMSDOS}, +{"OTD",0,_OUTD}, +{"OTI",0,_OUTI}, +{"SHL",0,_SLA}, +{"SHR",0,_SRL}, +{"STRUCT",0,__STRUCT}, +{"ENDSTRUCT",0,__ENDSTRUCT}, +{"ENDS",0,__ENDSTRUCT}, +{"NOEXPORT",0,__NOEXPORT}, +{"ENOEXPORT",0,__ENOEXPORT}, +{"MODULE",0,__MODULE}, +{"ENDMODULE",0,__ENDMODULE}, +{"TIMESTAMP",0,__TIMESTAMP}, +{"SUMMEM",0,__SUMMEM}, +{"XORMEM",0,__XORMEM}, +{"CIPHERMEM",0,__CIPHERMEM}, +{"EXTERNAL",0,__EXTERNAL}, +{"PROCEDURE",0,__PROCEDURE}, +{"",0,NULL} +}; + +int IsDirective(char *zeexpression) +{ + int i,crc; + + crc=GetCRC(zeexpression); + + for (i=0;instruction[i].mnemo[0];i++) if (instruction[i].crc==crc && !strcmp(instruction[i].mnemo,zeexpression)) return 1; + + return 0; +} + +int Assemble(struct s_assenv *ae, unsigned char **dataout, int *lenout, struct s_rasm_info **debug) +{ + #undef FUNC + #define FUNC "Assemble" + + unsigned char *AmsdosHeader; + struct s_expression curexp={0}; + struct s_wordlist *wordlist; + struct s_label *curlabel; + int icrc,curcrc,i,j,k; + unsigned char *lzdata=NULL; + int lzlen,lzshift,input_size; + int slzlen,delta; + unsigned char *input_data; + struct s_orgzone orgzone={0}; + int iorgzone,ibank,offset,endoffset,morgzone,saveorgzone; + int AutomateCharStop[256]; + int AutomateChar[256]; + int il,jl,maxrom; + char *TMP_filename=NULL; + int minmem=65536,maxmem=0,lzmove; + char symbol_line[1024]; + int ifast,executed; + /* debug */ + int curii,inhibe; + int ok; + + + for (i=0;i<256;i++) { + if (i==0 || (i>='a' && i<='z') || (i>='A' && i<='Z')) AutomateCharStop[i]=1; else AutomateCharStop[i]=0; + if ((i>='a' && i<='z') || (i>='A' && i<='Z')) AutomateChar[i]=1; else AutomateChar[i]=0; + } + AutomateChar['@']=AutomateCharStop['@']=1; + AutomateChar['_']=AutomateCharStop['_']=1; + + rasm_printf(ae,KAYGREEN"Assembling\n"); +#if TRACE_ASSEMBLE +printf("assembling (nberr=%d)\n",ae->nberr); +#endif +#if TRACE_GENERALE +printf("*** assembling ***\n"); +#endif + + ae->retdebug=debug; + + srand((unsigned)time(0)); + + wordlist=ae->wl; + ae->wl=wordlist; + /* start outside crunched section */ + ae->lz=-1; + + /* default orgzone */ + orgzone.ibank=BANK_MAX_NUMBER; + orgzone.inplace=1; + ObjectArrayAddDynamicValueConcat((void**)&ae->orgzone,&ae->io,&ae->mo,&orgzone,sizeof(orgzone)); + ___output=___internal_output; + /* init des automates */ + InitAutomate(ae->AutomateHexa,(unsigned char *)AutomateHexaDefinition); + InitAutomate(ae->AutomateDigit,(unsigned char *)AutomateDigitDefinition); + InitAutomate(ae->AutomateValidLabel,(unsigned char *)AutomateValidLabelDefinition); + InitAutomate(ae->AutomateValidLabelFirst,(unsigned char *)AutomateValidLabelFirstDefinition); + InitAutomate(ae->AutomateExpressionValidCharExtended,(unsigned char *)AutomateExpressionValidCharExtendedDefinition); + InitAutomate(ae->AutomateExpressionValidCharFirst,(unsigned char *)AutomateExpressionValidCharFirstDefinition); + InitAutomate(ae->AutomateExpressionValidChar,(unsigned char *)AutomateExpressionValidCharDefinition); + ae->AutomateExpressionDecision['<']='<'; + ae->AutomateExpressionDecision['>']='>'; + ae->AutomateExpressionDecision['=']='='; + ae->AutomateExpressionDecision['!']='!'; + ae->AutomateExpressionDecision[0]='E'; + /* gestion d'alias */ + ae->AutomateExpressionDecision['~']='~'; + /* set operator precedence */ + if (!ae->maxam) { + for (i=0;i<256;i++) { + ae->AutomateElement[i].string=NULL; + switch (i) { + /* priority 0 */ + case '(':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_OPEN;ae->AutomateElement[i].priority=0;break; + case ')':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_CLOSE;ae->AutomateElement[i].priority=0;break; + /* priority 1 */ + case 'b':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_NOT;ae->AutomateElement[i].priority=1;break; + /* priority 2 */ + case '*':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_MUL;ae->AutomateElement[i].priority=2;break; + case '/':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_DIV;ae->AutomateElement[i].priority=2;break; + case 'm':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_MOD;ae->AutomateElement[i].priority=2;break; + /* priority 3 */ + case '+':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_ADD;ae->AutomateElement[i].priority=3;break; + case '-':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_SUB;ae->AutomateElement[i].priority=3;break; + /* priority 4 */ + case '[':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_SHL;ae->AutomateElement[i].priority=4;break; + case ']':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_SHR;ae->AutomateElement[i].priority=4;break; + /* priority 5 */ + case 'l':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_LOWER;ae->AutomateElement[i].priority=5;break; + case 'g':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_GREATER;ae->AutomateElement[i].priority=5;break; + case 'e':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_EQUAL;ae->AutomateElement[i].priority=5;break; + case 'n':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_NOTEQUAL;ae->AutomateElement[i].priority=5;break; + case 'k':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_LOWEREQ;ae->AutomateElement[i].priority=5;break; + case 'h':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_GREATEREQ;ae->AutomateElement[i].priority=5;break; + /* priority 6 */ + case '&':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_AND;ae->AutomateElement[i].priority=6;break; + /* priority 7 */ + case '^':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_XOR;ae->AutomateElement[i].priority=7;break; + /* priority 8 */ + case '|':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_OR;ae->AutomateElement[i].priority=8;break; + /* priority 9 */ + case 'a':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_BAND;ae->AutomateElement[i].priority=9;break; + /* priority 10 */ + case 'o':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_BOR;ae->AutomateElement[i].priority=10;break; + default:ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_END; + } + } + } else { + for (i=0;i<256;i++) { + ae->AutomateElement[i].string=NULL; + switch (i) { + /* priority 0 */ + case '(':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_OPEN;ae->AutomateElement[i].priority=0;break; + case ')':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_CLOSE;ae->AutomateElement[i].priority=0;break; + /* priority 0.5 */ + case 'b':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_NOT;ae->AutomateElement[i].priority=128;break; + /* priority 1 */ + case '*':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_MUL;ae->AutomateElement[i].priority=464;break; + case '/':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_DIV;ae->AutomateElement[i].priority=464;break; + case 'm':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_MOD;ae->AutomateElement[i].priority=464;break; + case '+':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_ADD;ae->AutomateElement[i].priority=464;break; + case '-':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_SUB;ae->AutomateElement[i].priority=464;break; + case '[':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_SHL;ae->AutomateElement[i].priority=464;break; + case ']':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_SHR;ae->AutomateElement[i].priority=464;break; + case '&':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_AND;ae->AutomateElement[i].priority=464;break; + case '^':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_XOR;ae->AutomateElement[i].priority=464;break; + case '|':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_OR;ae->AutomateElement[i].priority=464;break; + /* priority 2 */ + case 'l':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_LOWER;ae->AutomateElement[i].priority=664;break; + case 'g':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_GREATER;ae->AutomateElement[i].priority=664;break; + case 'e':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_EQUAL;ae->AutomateElement[i].priority=664;break; + case 'n':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_NOTEQUAL;ae->AutomateElement[i].priority=664;break; + case 'k':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_LOWEREQ;ae->AutomateElement[i].priority=664;break; + case 'h':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_GREATEREQ;ae->AutomateElement[i].priority=664;break; + /* priority 3 */ + case 'a':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_BAND;ae->AutomateElement[i].priority=6128;break; + case 'o':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_BOR;ae->AutomateElement[i].priority=6128;break; + default:ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_END; + } + } + } + + /* psg conversion */ + for (i=j=0;i<100;i++) ae->psgtab[j++]=0; + for (i=0;i<49;i++) ae->psgtab[j++]=13; + for (i=0;i<35;i++) ae->psgtab[j++]=14; + for (i=0;i<72;i++) ae->psgtab[j++]=15; + if (j!=256) { + rasm_printf(ae,"Internal error with PSG conversion table\n"); + exit(-44); + } + for (i=j=0;i<1;i++) ae->psgfine[j++]=0; + for (i=0;i<1;i++) ae->psgfine[j++]=1; + for (i=0;i<1;i++) ae->psgfine[j++]=2; + for (i=0;i<2;i++) ae->psgfine[j++]=3; + for (i=0;i<2;i++) ae->psgfine[j++]=4; + for (i=0;i<2;i++) ae->psgfine[j++]=5; + for (i=0;i<3;i++) ae->psgfine[j++]=6; + for (i=0;i<4;i++) ae->psgfine[j++]=7; + for (i=0;i<7;i++) ae->psgfine[j++]=8; + for (i=0;i<9;i++) ae->psgfine[j++]=9; + for (i=0;i<13;i++) ae->psgfine[j++]=10; + for (i=0;i<19;i++) ae->psgfine[j++]=11; + for (i=0;i<27;i++) ae->psgfine[j++]=12; + for (i=0;i<37;i++) ae->psgfine[j++]=13; + for (i=0;i<53;i++) ae->psgfine[j++]=14; + for (i=0;i<75;i++) ae->psgfine[j++]=15; + if (j!=256) { + rasm_printf(ae,"Internal error with PSG conversion table\n"); + exit(-44); + } + /* default var */ + ae->autorise_export=1; + ExpressionSetDicoVar(ae,"PI",3.1415926545,0); + ExpressionSetDicoVar(ae,"ASSEMBLER_RASM",1,0); + + /* add a fictive expression to simplify test when parsing expressions */ + ObjectArrayAddDynamicValueConcat((void **)&ae->expression,&ae->ie,&ae->me,&curexp,sizeof(curexp)); + + /* compute CRC for keywords and directives */ + for (icrc=0;instruction[icrc].mnemo[0];icrc++) instruction[icrc].crc=GetCRC(instruction[icrc].mnemo); + for (icrc=0;math_keyword[icrc].mnemo[0];icrc++) math_keyword[icrc].crc=GetCRC(math_keyword[icrc].mnemo); + + if (ae->as80==1 || ae->pasmo) { /* not for UZ80 */ + for (icrc=0;instruction[icrc].mnemo[0];icrc++) { + if (strcmp(instruction[icrc].mnemo,"DEFB")==0 || strcmp(instruction[icrc].mnemo,"DB")==0) { + instruction[icrc].makemnemo=_DEFB_as80; + } else if (strcmp(instruction[icrc].mnemo,"DEFW")==0 || strcmp(instruction[icrc].mnemo,"DW")==0) { + instruction[icrc].makemnemo=_DEFW_as80; + } else if (strcmp(instruction[icrc].mnemo,"DEFI")==0) { + instruction[icrc].makemnemo=_DEFI_as80; + } + } + } else { + /* for multiple configurations with rasm embedded */ + for (icrc=0;instruction[icrc].mnemo[0];icrc++) { + if (strcmp(instruction[icrc].mnemo,"DEFB")==0 || strcmp(instruction[icrc].mnemo,"DB")==0) { + instruction[icrc].makemnemo=_DEFB; + } else if (strcmp(instruction[icrc].mnemo,"DEFW")==0 || strcmp(instruction[icrc].mnemo,"DW")==0) { + instruction[icrc].makemnemo=_DEFW; + } else if (strcmp(instruction[icrc].mnemo,"DEFI")==0) { + instruction[icrc].makemnemo=_DEFI; + } + } + } + + for (icrc=0;instruction[icrc].mnemo[0];icrc++) { + /* get indexes for DEF instructions */ + if (strcmp(instruction[icrc].mnemo,"DEFB")==0) { + ICRC_DEFB=icrc; + } else if (strcmp(instruction[icrc].mnemo,"DB")==0) { + ICRC_DB=icrc; + } else if (strcmp(instruction[icrc].mnemo,"DEFW")==0) { + ICRC_DEFW=icrc; + } else if (strcmp(instruction[icrc].mnemo,"DW")==0) { + ICRC_DW=icrc; + } else if (strcmp(instruction[icrc].mnemo,"DEFF")==0) { + ICRC_DEFF=icrc; + } else if (strcmp(instruction[icrc].mnemo,"DF")==0) { + ICRC_DF=icrc; + } else if (strcmp(instruction[icrc].mnemo,"DEFR")==0) { + ICRC_DEFR=icrc; + } else if (strcmp(instruction[icrc].mnemo,"DR")==0) { + ICRC_DR=icrc; + } else if (strcmp(instruction[icrc].mnemo,"DEFS")==0) { + ICRC_DEFS=icrc; + } else if (strcmp(instruction[icrc].mnemo,"DS")==0) { + ICRC_DS=icrc; + } else if (strcmp(instruction[icrc].mnemo,"DEFI")==0) { + ICRC_DEFI=icrc; + } + } + + /* Execution des mots clefs */ + /********************************************************** + A S S E M B L I N G M A I N L O O P + **********************************************************/ +#if TRACE_ASSEMBLE +printf("init ok\n"); +#endif +#if TRACE_GENERALE +printf("-loop\n"); +#endif + + ae->idx=1; + while (wordlist[ae->idx].t!=2) { + curcrc=GetCRC(wordlist[ae->idx].w); + /********************* + d e b u g i n f o + *********************/ + #if TRACE_ASSEMBLE + { + int iiii=0; + printf(KVERBOSE"%d [%s] L%d [%s]e=%d ",ae->idx,ae->filename[wordlist[ae->idx].ifile],wordlist[ae->idx].l,wordlist[ae->idx].w,wordlist[ae->idx].e); + while (!wordlist[ae->idx+iiii++].t) rasm_printf(ae," [%s]e=%d ",wordlist[ae->idx+iiii].w,wordlist[ae->idx+iiii].e); + + for (iiii=0;iiiiimacropos;iiii++) { + printf("M[%d] s=%d e=%d ",iiii,ae->macropos[iiii].start,ae->macropos[iiii].end); + } + printf("\n"); + } + #endif + + /******************************************************************** + c o n d i t i o n n a l a s s e m b l y m a n a g e m e n t + ********************************************************************/ + if (ae->ii || ae->isw) { + /* inhibition of if/endif */ + for (inhibe=curii=0;curiiii;curii++) { + if (!ae->ifthen[curii].v || ae->ifthen[curii].v==-1) { + inhibe=1; + break; + } + } + /* when inhibited we are looking only for a IF/IFDEF/IFNOT/IFNDEF/ELSE/ELSEIF/ENDIF or SWITCH/CASE/DEFAULT/ENDSWITCH */ + if (inhibe) { + /* this section does NOT need to be agressively optimized !!! */ + if (curcrc==CRC_ELSEIF && strcmp(wordlist[ae->idx].w,"ELSEIF")==0) { + /* true IF needs to be done ONLY on the active level */ + if (curii==ae->ii-1) __ELSEIF(ae); else __ELSEIF_light(ae); + } else if (curcrc==CRC_ELSE && strcmp(wordlist[ae->idx].w,"ELSE")==0) { + __ELSE(ae); + } else if (curcrc==CRC_ENDIF && strcmp(wordlist[ae->idx].w,"ENDIF")==0) { + __ENDIF(ae); + } else if (curcrc==CRC_IF && strcmp(wordlist[ae->idx].w,"IF")==0) { + /* as we are inhibited we do not have to truly compute IF */ + __IF_light(ae); + } else if (curcrc==CRC_IFDEF && strcmp(wordlist[ae->idx].w,"IFDEF")==0) { + __IFDEF_light(ae); + } else if (curcrc==CRC_IFNOT && strcmp(wordlist[ae->idx].w,"IFNOT")==0) { + __IFNOT_light(ae); + } else if (curcrc==CRC_IFUSED && strcmp(wordlist[ae->idx].w,"IFUSED")==0) { + __IFUSED_light(ae); + } else if (curcrc==CRC_IFNUSED && strcmp(wordlist[ae->idx].w,"IFNUSED")==0) { + __IFNUSED_light(ae); + } else if (curcrc==CRC_IFNDEF && strcmp(wordlist[ae->idx].w,"IFNDEF")==0) { + __IFNDEF_light(ae); + } else if (curcrc==CRC_SWITCH && strcmp(wordlist[ae->idx].w,"SWITCH")==0) { + __SWITCH_light(ae); + } else if (curcrc==CRC_CASE && strcmp(wordlist[ae->idx].w,"CASE")==0) { + __CASE_light(ae); + } else if (curcrc==CRC_ENDSWITCH && strcmp(wordlist[ae->idx].w,"ENDSWITCH")==0) { + __ENDSWITCH(ae); + } else if (curcrc==CRC_BREAK && strcmp(wordlist[ae->idx].w,"BREAK")==0) { + __BREAK_light(ae); + } else if (curcrc==CRC_DEFAULT && strcmp(wordlist[ae->idx].w,"DEFAULT")==0) { + __DEFAULT_light(ae); + } + while (wordlist[ae->idx].t==0) ae->idx++; + ae->idx++; + continue; + } else { + /* inhibition of switch/case */ + for (curii=0;curiiisw;curii++) { + if (!ae->switchcase[curii].execute) { + inhibe=2; + break; + } + } + if (inhibe) { + /* this section does NOT need to be agressively optimized !!! */ + if (curcrc==CRC_CASE && strcmp(wordlist[ae->idx].w,"CASE")==0) { + __CASE(ae); + } else if (curcrc==CRC_ENDSWITCH && strcmp(wordlist[ae->idx].w,"ENDSWITCH")==0) { + __ENDSWITCH(ae); + } else if (curcrc==CRC_IF && strcmp(wordlist[ae->idx].w,"IF")==0) { + /* as we are inhibited we do not have to truly compute IF */ + __IF_light(ae); + } else if (curcrc==CRC_IFDEF && strcmp(wordlist[ae->idx].w,"IFDEF")==0) { + __IFDEF(ae); + } else if (curcrc==CRC_IFNOT && strcmp(wordlist[ae->idx].w,"IFNOT")==0) { + __IFNOT(ae); + } else if (curcrc==CRC_ELSE && strcmp(wordlist[ae->idx].w,"ELSE")==0) { + __ELSE(ae); + } else if (curcrc==CRC_ENDIF && strcmp(wordlist[ae->idx].w,"ENDIF")==0) { + __ENDIF(ae); + } else if (curcrc==CRC_ELSEIF && strcmp(wordlist[ae->idx].w,"ELSEIF")==0) { + __ELSEIF(ae); + } else if (curcrc==CRC_IFUSED && strcmp(wordlist[ae->idx].w,"IFUSED")==0) { + __IFUSED(ae); + } else if (curcrc==CRC_IFNUSED && strcmp(wordlist[ae->idx].w,"IFNUSED")==0) { + __IFNUSED(ae); + } else if (curcrc==CRC_IFNDEF && strcmp(wordlist[ae->idx].w,"IFNDEF")==0) { + __IFNDEF(ae); + } else if (curcrc==CRC_SWITCH && strcmp(wordlist[ae->idx].w,"SWITCH")==0) { + __SWITCH(ae); + } else if (curcrc==CRC_BREAK && strcmp(wordlist[ae->idx].w,"BREAK")==0) { + __BREAK(ae); + } else if (curcrc==CRC_DEFAULT && strcmp(wordlist[ae->idx].w,"DEFAULT")==0) { + __DEFAULT(ae); + } + while (wordlist[ae->idx].t==0) ae->idx++; + ae->idx++; + continue; + } + } + } + /***************************************** + m a c r o p o s i t i o n s + *****************************************/ + if (ae->imacropos) { + int icheckm; + + /* + printf("===== Macro positions idx=%d =====\n",ae->idx); + for (icheckm=0;icheckmimacropos;icheckm++) { + printf("macro[%d] start=%3d end=%3d level=%d \n",icheckm,ae->macropos[icheckm].start,ae->macropos[icheckm].end,ae->macropos[icheckm].level); + } + printf("---------------------------\n"); + */ + + /* we must close */ + for (icheckm=0;icheckmimacropos;icheckm++) { + if (ae->idx==ae->macropos[icheckm].end) { + /* contiguous macro management... */ + if (ae->macropos[icheckm].pushed) { + PopGlobal(ae); + ae->macropos[icheckm].pushed=0; + } + } + } + /* before opening */ + for (icheckm=0;icheckmimacropos;icheckm++) { + if (ae->idx==ae->macropos[icheckm].start) { + PushGlobal(ae); + ae->macropos[icheckm].pushed=1; + } + } + + /* are we still in a macro? */ + if (ae->idx>=ae->macropos[0].end) { + /* are we out of all repetition blocks? */ + if (!ae->ir && !ae->iw) { + ae->imacropos=0; + } + } + } + /***************************************** + e x e c u t e i n s t r u c t i o n + *****************************************/ + executed=0; + if ((ifast=ae->fastmatch[(int)wordlist[ae->idx].w[0]])!=-1) { + while (instruction[ifast].mnemo[0]==wordlist[ae->idx].w[0]) { + if (instruction[ifast].crc==curcrc && strcmp(instruction[ifast].mnemo,wordlist[ae->idx].w)==0) { +#if TRACE_ASSEMBLE +printf("-> mnemo\n"); +#endif + instruction[ifast].makemnemo(ae); + executed=1; + break; + } + ifast++; + } + } + /***************************************** + e x e c u t e m a c r o + *****************************************/ + if (!executed) { + /* is it a macro? */ + if ((ifast=SearchMacro(ae,curcrc,wordlist[ae->idx].w))>=0) { +#if TRACE_ASSEMBLE +printf("-> macro\n"); +#endif + wordlist=__MACRO_EXECUTE(ae,ifast); + continue; + } + } + /********************************************************************* + e x e c u t e e x p r e s s i o n o r p u s h l a b e l + *********************************************************************/ + if (!ae->stop) { + if (!executed) { + /* no instruction executed, this is a label or an assignement */ + if (wordlist[ae->idx].e) { +#if TRACE_ASSEMBLE +printf("-> expr\n"); +#endif + ExpressionFastTranslate(ae,&wordlist[ae->idx].w,0); + ComputeExpression(ae,wordlist[ae->idx].w,ae->codeadr,0,0); + } else { +#if TRACE_ASSEMBLE +printf("-> label\n"); +#endif + PushLabel(ae); + } + } else { +#if TRACE_ASSEMBLE +printf("-> ajuste IDX\n"); +#endif + while (!wordlist[ae->idx].t) { + ae->idx++; + } + } + ae->idx++; + } else { +#if TRACE_ASSEMBLE +printf("-> STOP\n"); +#endif + break; + } + } +#if TRACE_ASSEMBLE + rasm_printf(ae,KVERBOSE"%d [%s] L%d [%s] fin de la liste de mots\n",ae->idx,ae->filename[wordlist[ae->idx].ifile],wordlist[ae->idx].l,wordlist[ae->idx].w); + printf("check ORG\n"); +#endif +#if TRACE_GENERALE +printf("-check ORG\n"); +#endif + + if (!ae->stop) { + /* end of assembly, check there is no opened struct */ + if (ae->getstruct) { + MakeError(ae,ae->backup_filename,ae->backup_line,"STRUCT declaration was not closed\n"); + } + /* end of assembly, close the last ORG zone */ + if (ae->io) { + ae->orgzone[ae->io-1].memend=ae->outputadr; + } + OverWriteCheck(ae); + /* end of assembly, close crunched zone (if any) */ + __internal_UpdateLZBlockIfAny(ae); + + /* end of assembly, check for opened repeat and opened while loop */ + for (i=0;iir;i++) { + MakeError(ae,ae->filename[wordlist[ae->repeat[i].start].ifile],wordlist[ae->repeat[i].start].l,"REPEAT was not closed\n"); + } + for (i=0;iiw;i++) { + MakeError(ae,ae->filename[wordlist[ae->whilewend[i].start].ifile],wordlist[ae->whilewend[i].start].l,"WHILE was not closed\n"); + } + /* is there any IF opened? -> need an evolution for a better error message */ + for (i=0;iii;i++) { + char instr[32]; + switch (ae->ifthen[i].type) { + case E_IFTHEN_TYPE_IF:strcpy(instr,"IF");break; + case E_IFTHEN_TYPE_IFNOT:strcpy(instr,"IFNOT");break; + case E_IFTHEN_TYPE_IFDEF:strcpy(instr,"IFDEF");break; + case E_IFTHEN_TYPE_IFNDEF:strcpy(instr,"IFNDEF");break; + case E_IFTHEN_TYPE_ELSE:strcpy(instr,"ELSE");break; + case E_IFTHEN_TYPE_ELSEIF:strcpy(instr,"ELSEIF");break; + case E_IFTHEN_TYPE_IFUSED:strcpy(instr,"IFUSED");break; + case E_IFTHEN_TYPE_IFNUSED:strcpy(instr,"IFNUSED");break; + default:strcpy(instr,""); + } + MakeError(ae,ae->ifthen[i].filename,ae->ifthen[i].line,"%s conditionnal block was not closed\n",instr); + } + } +#if TRACE_ASSEMBLE +printf("crunch if any %d blocks\n",ae->ilz); +#endif + /*************************************************** + c r u n c h L Z s e c t i o n s + ***************************************************/ + if (!ae->stop || !ae->nberr) { + + /* all EQU values are computed in order to be STATIC values until the end + * at this point, there is a lot of expressions (in or outside lz sections) + * to be computed. + */ + for (i=0;iialias;i++) { + char alias_value[128]; + double v; + // compute EQU defined in crunched sections + if (ae->alias[i].lz>=0) { + ae->idx=ae->alias[i].iw; // expression core hack + v=ComputeExpressionCore(ae,ae->alias[i].translation,ae->alias[i].ptr,0); + sprintf(alias_value,"%.8lf",v); + MemFree(ae->alias[i].translation); + ae->alias[i].translation=TxtStrDup(alias_value); + ae->alias[i].len=strlen(ae->alias[i].translation); + } + } + + for (i=0;iilz;i++) { + /* on dépile les symboles dans l'ordre mais on ne reloge pas sur les zones intermédiaires ou post-crunched */ + if (ae->lzsection[i].lzversion!=0) { +#if TRACE_ASSEMBLE +printf("Crunch LZ[%d] (%d) %s\n",i,ae->lzsection[i].lzversion,ae->lzsection[i].lzversion==8?"mizou":""); +#endif + + if (ae->lzsection[i].memend==-1) { + /* patch idx */ + ae->idx=ae->lzsection[i].iw; + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Crunched section was not closed\n"); + continue; + } + + /* compute labels and expression inside crunched blocks */ + PopAllExpression(ae,i); + + ae->curlz=i; + iorgzone=ae->lzsection[i].iorgzone; + ibank=ae->lzsection[i].ibank; + input_data=&ae->mem[ae->lzsection[i].ibank][ae->lzsection[i].memstart]; + input_size=ae->lzsection[i].memend-ae->lzsection[i].memstart; + if (!input_size) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: crunched section is empty\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + if (ae->erronwarn) MaxError(ae); + } else { + switch (ae->lzsection[i].lzversion) { + + case 70: + #ifndef NO_3RD_PARTIES + if (input_size>=1024 && MAX_OFFSET_ZX0>5000) rasm_printf(ae,KWARNING"ZX0 is crunching %.1fkb this may take a while, be patient...\n",input_size/1024.0); + lzdata=zx0_compress(zx0_optimize(input_data, input_size, 0, MAX_OFFSET_ZX0), input_data, input_size, 0, 0, 1,&slzlen, &delta); + lzlen=slzlen; + #endif + break; + case 71: + #ifndef NO_3RD_PARTIES + if (input_size>=1024 && MAX_OFFSET_ZX0>5000) rasm_printf(ae,KWARNING"ZX0 is crunching %.1fkb this may take a while, be patient...\n",input_size/1024.0); + zx0_reverse(input_data,input_data+input_size-1); + lzdata=zx0_compress(zx0_optimize(input_data, input_size, 0, MAX_OFFSET_ZX0), input_data, input_size, 0, 1, 0,&slzlen, &delta); + zx0_reverse(lzdata,lzdata+slzlen-1); + lzlen=slzlen; + #endif + break; + case 7: + #ifndef NO_3RD_PARTIES + lzdata=ZX7_compress(zx7_optimize(input_data, input_size), input_data, input_size, &slzlen); + lzlen=slzlen; + #endif + break; + case 4: + #ifndef NO_3RD_PARTIES + lzdata=LZ4_crunch(input_data,input_size,&lzlen); + #endif + break; + case 8: + #ifndef NO_3RD_PARTIES + if (input_size>=1024) rasm_printf(ae,KWARNING"Exomizer is crunching %.1fkb this may take a while, be patient...\n",input_size/1024.0); + lzdata=Exomizer_crunch(input_data,input_size,&lzlen); + #endif + break; + case 17: + #ifndef NO_3RD_PARTIES + if (input_size>=1024) rasm_printf(ae,KWARNING"AP-Ultra is crunching %.1fkb this may take a while, be patient...\n",input_size/1024.0); + APULTRA_crunch(input_data,input_size,&lzdata,&lzlen); + #endif + break; + case 18: +#if TRACE_ASSEMBLE + printf("crunching bank %d ptr=%d lng=%d version=%d minmatch=%d\n",ae->lzsection[i].ibank,ae->lzsection[i].memstart,input_size,ae->lzsection[i].version,ae->lzsection[i].minmatch); +#endif + #ifndef NO_3RD_PARTIES + if (input_size>=16384 && ae->lzsection[i].version==2) rasm_printf(ae,KWARNING"LZSA is crunching %.1fkb this may take a while, be patient...\n",input_size/1024.0); + LZSA_crunch(input_data,input_size,&lzdata,&lzlen,ae->lzsection[i].version,ae->lzsection[i].minmatch); + #endif + break; + case 48: + lzdata=LZ48_crunch(input_data,input_size,&lzlen); + break; + case 49: + lzdata=LZ49_crunch(input_data,input_size,&lzlen); + break; + default: + rasm_printf(ae,"Internal error - unknown crunch method %d\n",ae->lzsection[i].lzversion); + exit(-12); + } + } + +#if TRACE_ASSEMBLE + printf("lzsection[%d] type=%d start=%04X end=%04X crunched size=%d\n",i,ae->lzsection[i].lzversion,ae->lzsection[i].memstart,ae->lzsection[i].memend,lzlen); +#endif + + if (input_sizefilename[ae->wl[ae->lzsection[i].iw].ifile],ae->wl[ae->lzsection[i].iw].l,"As the LZ section cannot crunch data, Rasm may not guarantee assembled file!\n"); + rasm_printf(ae,KWARNING"Warning: LZ section is bigger than original\n"); + if (ae->erronwarn) MaxError(ae); + } + + lzshift=lzlen-(ae->lzsection[i].memend-ae->lzsection[i].memstart); +#if TRACE_ASSEMBLE +printf("lzshift=%d\n",lzshift); +#endif + + /******************************************************************************* + r e l o c a t e d a t a u n t i l n o n c o n t i g u o u s O R G + *******************************************************************************/ + morgzone=iorgzone; + if (lzshift>0) { + /* positif => plus gros @@TODO */ + //MemMove(ae->mem[ae->lzsection[i].ibank]+ae->lzsection[i].memend+lzshift,ae->mem[ae->lzsection[i].ibank]+ae->lzsection[i].memend,65536-ae->lzsection[i].memend-lzshift); + } else if (lzshift<0) { + /* when crunched we may have to move more than 1 ORG */ + while (morgzone+1io) { + /* if next ORG zone is contiguous */ + if (ae->orgzone[morgzone+1].memstart==ae->orgzone[morgzone].memend && ae->orgzone[morgzone+1].ibank==ae->orgzone[morgzone].ibank) { + morgzone++; + } else break; + } + lzmove=ae->orgzone[morgzone].memend-ae->lzsection[i].memend; +#if TRACE_ASSEMBLE +printf("include %d other ORG for the memove size=%d\n",morgzone-iorgzone,lzmove); +#endif + if (lzmove) { + MemMove(ae->mem[ae->lzsection[i].ibank]+ae->lzsection[i].memend+lzshift,ae->mem[ae->lzsection[i].ibank]+ae->lzsection[i].memend,lzmove); + } + } + memcpy(ae->mem[ae->lzsection[i].ibank]+ae->lzsection[i].memstart,lzdata,lzlen); + MemFree(lzdata); + /******************************************************************* + l a b e l a n d e x p r e s s i o n r e l o c a t i o n + *******************************************************************/ + /* relocate labels in the same ORG zone AND contiguous ORG when they are "in place" */ + il=ae->lzsection[i].ilabel; + saveorgzone=iorgzone; + do { + while (ilil && ae->label[il].iorgzoneil && ae->label[il].iorgzone==iorgzone) { + curlabel=SearchLabel(ae,ae->label[il].iw!=-1?wordlist[ae->label[il].iw].w:ae->label[il].name,ae->label[il].crc); + /* CANNOT be NULL */ + curlabel->ptr+=lzshift; +#if TRACE_ASSEMBLE + printf("label [%s] shifte de %d valeur #%04X -> #%04X\n",curlabel->iw!=-1?wordlist[curlabel->iw].w:curlabel->name,lzshift,curlabel->ptr-lzshift,curlabel->ptr); +#endif + il++; + } + iorgzone++; + /* jump over contiguous ORG not "in place" */ + while (iorgzoneio && !ae->orgzone[iorgzone].inplace && iorgzone<=morgzone) { + //printf("label reallocation jump over ORG %d\n",iorgzone); + iorgzone++; + } + } while (iorgzone<=morgzone); + + /* relocate mapping after the same ORG zone and inside contiguous ORG + * there is no check for outside/inside crunched section because this + * was already done during mapping declaration but we must avoid to + * shift before crunched section inside the same ORG */ + iorgzone=saveorgzone; + do { + for (il=0;ilnexternal;il++) { + for (jl=0;jlexternal[il].nmapping;jl++) { + if (ae->external[il].mapping[jl].iorgzone==iorgzone && ae->external[il].mapping[jl].ptr>ae->lzsection[i].memstart) { + //printf("shift mapping ptr=%d => %d\n",ae->external[il].mapping[jl].ptr,ae->external[il].mapping[jl].ptr+lzshift); + ae->external[il].mapping[jl].ptr+=lzshift; + } + } + } + iorgzone++; + } while (iorgzone<=morgzone); + + /* relocate expressions in the same ORG zone AND contiguous ORG */ + iorgzone=saveorgzone; + il=ae->lzsection[i].iexpr; + do { + while (ilil && ae->label[il].iorgzoneie && ae->expression[il].iorgzone==iorgzone) { + ae->expression[il].wptr+=lzshift; + /* relocate only "in place" contiguous ORG */ + if (ae->orgzone[iorgzone].inplace) ae->expression[il].ptr+=lzshift; +#if TRACE_ASSEMBLE + printf("expression [%s] shiftee ptr(%s)=#%04X wptr=#%04X\n", ae->expression[il].reference?ae->expression[il].reference:wordlist[ae->expression[il].iw].w, ae->orgzone[iorgzone].inplace?"relocated":"untouched",ae->expression[il].ptr, ae->expression[il].wptr); +#endif + il++; + } + iorgzone++; + } while (iorgzone<=morgzone); + + /* relocate crunched sections in the same ORG zone AND contiguous ORG */ + iorgzone=saveorgzone; + il=i+1; + do { + while (ililz && ae->lzsection[il].iorgzone==iorgzone && ae->lzsection[il].ibank==ibank) { + +#if TRACE_ASSEMBLE + rasm_printf(ae,"reloger lzsection[%d] O%d B%d shift=%d\n",il,ae->lzsection[il].iorgzone,ae->lzsection[il].ibank,lzshift); +#endif + ae->lzsection[il].memstart+=lzshift; + ae->lzsection[il].memend+=lzshift; + il++; + } + iorgzone++; + } while (iorgzone<=morgzone); + + iorgzone=saveorgzone; + /* relocate ORG zone(s) */ + ae->orgzone[iorgzone].memend+=lzshift; + while (iorgzoneorgzone[iorgzone].memstart+=lzshift; + ae->orgzone[iorgzone].memend+=lzshift; + } + } + } + for (i=0;iilz;i++) { + if (ae->lzsection[i].lzversion==0) { +#if TRACE_ASSEMBLE +//printf("PopAllExpr on intermediate section[%d] (%d) %s\n",i,ae->lzsection[i].lzversion,ae->lzsection[i].lzversion==8?"mizou":""); +#endif + /* compute labels and expression outside crunched blocks BUT after crunched */ + PopAllExpression(ae,i); + } + } + if (ae->ilz) { + /* compute expression placed after the last crunched block */ + PopAllExpression(ae,ae->ilz); + } + /* compute expression outside crunched blocks */ + PopAllExpression(ae,-1); + } + + /******************************************************************************* + p o k e r + *******************************************************************************/ + for (i=0;inbpoker;i++) { + int istart=-1,iend=-1; + unsigned char xorval,sumval; + + /* start/end */ + ae->idx=ae->poker[i].istart; /* exp hack */ + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + istart=RoundComputeExpression(ae,ae->wl[ae->idx].w,0,0,0); + ae->idx=ae->poker[i].iend; /* exp hack */ + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + iend=RoundComputeExpression(ae,ae->wl[ae->idx].w,0,0,0); + + switch (ae->poker[i].method) { + case E_POKER_XOR8: + xorval=0; + for (j=istart;jmem[ae->poker[i].ibank][j]; + } + ae->mem[ae->poker[i].ibank][ae->poker[i].outputadr]=xorval; + //printf("poker XOR from #%04X to #%04X at #%04X\n",istart,iend,ae->poker[i].outputadr); + break; + case E_POKER_SUM8: + sumval=0; + for (j=istart;jmem[ae->poker[i].ibank][j]; + } + ae->mem[ae->poker[i].ibank][ae->poker[i].outputadr]=sumval; + break; + case E_POKER_CIPHER001: + case E_POKER_CIPHER002: + if (ae->poker[i].method==E_POKER_CIPHER001) { + xorval=ae->mem[ae->poker[i].ibank][istart]; + istart++; + } else if (ae->poker[i].method==E_POKER_CIPHER002) { + xorval=istart&0xFF; // xor start value depends on memory location! + } + for (j=istart;jmem[ae->poker[i].ibank][j]=xorval=ae->mem[ae->poker[i].ibank][j]^xorval; + } + break; + case E_POKER_CIPHER003: + for (j=istart;jmem[ae->poker[i].ibank][j]=ae->mem[ae->poker[i].ibank][j]^xorval; + } + break; + case E_POKER_CIPHER004: + { + char *zekey; + int zelen,ikey=0; + zekey=TxtStrDup(ae->wl[ae->poker[i].istring].w+1); + zelen=strlen(zekey)-1; + if (zelen>1) { + zekey[zelen]=0; + for (j=istart;j=zelen) ikey=0; + ae->mem[ae->poker[i].ibank][j]=ae->mem[ae->poker[i].ibank][j]^xorval; + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CIPHER needs a string of one char or more to run properly\n"); + } + if (zekey) MemFree(zekey); + } + break; + default:printf("warning remover\n");break; + } + + for (j=0;jnbpoker;j++) { + if (ae->poker[i].ibank==ae->poker[j].ibank) { + if (ae->poker[j].outputadr>=istart && ae->poker[j].outputadrnowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: %s poker result is inside another %s poker calculation",GetCurrentFile(ae),ae->wl[ae->idx].l, + ae->poker[i].methodpoker[i].method]:"???", + ae->poker[j].methodpoker[j].method]:"???"); + ae->idx=ae->poker[j].istart; + rasm_printf(ae,KWARNING"[%s:%d]\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + if (ae->erronwarn) MaxError(ae); + } + } + } + } + + } + + /******************************************************************************* + d e l a y e d p r i n t s + *******************************************************************************/ + for (i=0;iidprint;i++) { + ae->idx=ae->dprint_idx[i]; + __PRINT(ae); + } + +/*************************************************************************************************************************************************************************************** +**************************************************************************************************************************************************************************************** + W R I T E O U T P U T F I L E S +**************************************************************************************************************************************************************************************** +***************************************************************************************************************************************************************************************/ + TMP_filename=MemMalloc(PATH_MAX); +#if 0 +for (i=0;iio;i++) { +printf("ORG[%02d] start=%04X end=%04X ibank=%d nocode=%d protect=%d\n",i,ae->orgzone[i].memstart,ae->orgzone[i].memend,ae->orgzone[i].ibank,ae->orgzone[i].nocode,ae->orgzone[i].protect); +} +#endif +#if TRACE_ASSEMBLE +printf("output files\n"); +#endif + + if (!ae->nberr && !ae->checkmode) { + + /* enregistrement des fichiers programmes par la commande SAVE */ + PopAllSave(ae); + + if (ae->nbsave==0 || ae->forcecpr || ae->forcesnapshot || ae->forceROM || ae->forcetape) { + /********************************************* + ROM LABEL EXPORT + *********************************************/ + char cprinfo_filename[PATH_MAX]; + char cprinfo_line[1024]; + + if (ae->cprinfo_export) { + for (i=maxrom=0;iio;i++) { + if (ae->orgzone[i].ibank<256 && ae->orgzone[i].ibank>maxrom) maxrom=ae->orgzone[i].ibank; + } + if (ae->cprinfo_filename) { + sprintf(cprinfo_filename,"%s",ae->cprinfo_filename); + } else { + sprintf(cprinfo_filename,"%s.rom_labels",ae->outputfilename); + } + FileRemoveIfExists(cprinfo_filename); + rasm_printf(ae,KIO"Write ROM label file %s\n",cprinfo_filename); + + for (i=0;i<=maxrom && iiwnamebank[i]>0) { + lm=strlen(ae->wl[ae->iwnamebank[i]].w)-2; + if (lm) { + snprintf(cprinfo_line,sizeof(cprinfo_line),"%d: %-*.*s\n",i,lm,lm,ae->wl[ae->iwnamebank[i]].w+1); + FileWriteLine(cprinfo_filename,cprinfo_line); + } + } else { + sprintf(cprinfo_line,"%d:\n",i); + FileWriteLine(cprinfo_filename,cprinfo_line); + } + } + FileWriteLineClose(cprinfo_filename); + } + + /********************************************* + ********************************************** + C A R T R I D G E + ********************************************** + *********************************************/ + if (ae->forcecpr) { + char ChunkName[32]; + int ChunkSize; + unsigned char chunk_endian; + + if (ae->cartridge_name) { + sprintf(TMP_filename,"%s",ae->cartridge_name); + } else { + if (!ae->extendedCPR) sprintf(TMP_filename,"%s.cpr",ae->outputfilename); + else sprintf(TMP_filename,"%s.xpr",ae->outputfilename); + } + FileRemoveIfExists(TMP_filename); + + rasm_printf(ae,KIO"Write %scartridge file %s\n",ae->extendedCPR?"extended ":"",TMP_filename); + for (i=maxrom=0;iio;i++) { + if (ae->orgzone[i].ibank<256 && ae->orgzone[i].ibank>maxrom) maxrom=ae->orgzone[i].ibank; + } + /* construction du CPR */ + /* header blablabla */ + strcpy(ChunkName,"RIFF"); + FileWriteBinary(TMP_filename,ChunkName,4); + + if (!ae->extendedCPR) { + ChunkSize=(maxrom+1)*(16384+8)+4; + chunk_endian=ChunkSize&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); + chunk_endian=(ChunkSize>>8)&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); + chunk_endian=(ChunkSize>>16)&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); + chunk_endian=(ChunkSize>>24)&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); + sprintf(ChunkName,"AMS!"); + FileWriteBinary(TMP_filename,ChunkName,4); + } else { + for (i=0;i<=maxrom;i+=32) { + char xproutputname[256]; + sprintf(xproutputname,"xpr%02d.rom",i>>5); + FileRemoveIfExists(xproutputname); + } + + ChunkSize=(maxrom+1)*(16384+8)+4+10; + chunk_endian=ChunkSize&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); + chunk_endian=(ChunkSize>>8)&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); + chunk_endian=(ChunkSize>>16)&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); + chunk_endian=(ChunkSize>>24)&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); + sprintf(ChunkName,"CXME"); + FileWriteBinary(TMP_filename,ChunkName,4); + ChunkName[0]='N'; + ChunkName[1]='B'; + ChunkName[2]='B'; + ChunkName[3]='K'; + FileWriteBinary(TMP_filename,ChunkName,4); + ChunkSize=2; + chunk_endian=ChunkSize&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); + chunk_endian=(ChunkSize>>8)&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); + chunk_endian=(ChunkSize>>16)&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); + chunk_endian=(ChunkSize>>24)&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); + ChunkName[0]=0; + ChunkName[1]=32; + FileWriteBinary(TMP_filename,ChunkName,2); + } + +// for (j=0;jio;j++) { +//printf("ORG[%03d]=B%02d/#%04X/#%04X\n",j,ae->orgzone[j].ibank,ae->orgzone[j].memstart,ae->orgzone[j].memend); +// } + for (i=0;i<=maxrom;i++) { + offset=65536; + endoffset=0; + for (j=0;jio;j++) { + if (ae->orgzone[j].protect) continue; /* protected zones exclusion */ + /* bank data may start anywhere (typically #0000 or #C000) */ + if (ae->orgzone[j].ibank==i && ae->orgzone[j].memstart!=ae->orgzone[j].memend) { + if (ae->orgzone[j].memstartorgzone[j].memstart; + if (ae->orgzone[j].memend>endoffset) endoffset=ae->orgzone[j].memend; + } + } + if (endoffset>offset) { + int lm=0; + if (ae->iwnamebank[i]>0) { + lm=strlen(ae->wl[ae->iwnamebank[i]].w)-2; + } + if (ae->cprinfo) rasm_printf(ae,KVERBOSE"WriteCPR bank %2d of %5d byte%s start at #%04X",i,endoffset-offset,endoffset-offset>1?"s":" ",offset); + if (endoffset-offset>16384) { + rasm_printf(ae,"\nROM %d is too big!!!\n",i); + FileWriteBinaryClose(TMP_filename); + FileRemoveIfExists(TMP_filename); + FreeAssenv(ae); + exit(ABORT_ERROR); + } + if (ae->cprinfo) { + if (lm) { + rasm_printf(ae," (%-*.*s)\n",lm,lm,ae->wl[ae->iwnamebank[i]].w+1); + } else { + rasm_printf(ae,"\n"); + } + } + } else { + if (ae->cprinfo) rasm_printf(ae,KVERBOSE"WriteCPR bank %2d (empty)\n",i); + } + ChunkSize=16384; + if (ae->extendedCPR) { + ChunkName[0]='C'; + ChunkName[1]='X'; + ChunkName[2]=i>>8; + ChunkName[3]=i&255; + } else sprintf(ChunkName,"cb%02d",i); + FileWriteBinary(TMP_filename,ChunkName,4); + chunk_endian=ChunkSize&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); + chunk_endian=(ChunkSize>>8)&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); + chunk_endian=(ChunkSize>>16)&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); + chunk_endian=(ChunkSize>>24)&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); + if (offset>0xC000) { + unsigned char filler[16384]={0}; + ChunkSize=65536-offset; + if (ChunkSize) FileWriteBinary(TMP_filename,(char*)ae->mem[i]+offset,ChunkSize); + /* ADD zeros until the end of the bank */ + FileWriteBinary(TMP_filename,(char*)filler,16384-ChunkSize); + if (ae->xpr) { + char xproutputname[256]; + sprintf(xproutputname,"xpr%02d.rom",i>>5); + if (ChunkSize) FileWriteBinary(xproutputname,(char*)ae->mem[i]+offset,ChunkSize); + FileWriteBinary(xproutputname,(char*)filler,16384-ChunkSize); + } + } else { + FileWriteBinary(TMP_filename,(char*)ae->mem[i]+offset,ChunkSize); + if (ae->xpr) { + char xproutputname[256]; + sprintf(xproutputname,"xpr%02d.rom",i>>5); + FileWriteBinary(xproutputname,(char*)ae->mem[i]+offset,ChunkSize); + } + } + } + FileWriteBinaryClose(TMP_filename); + rasm_printf(ae,"Total %d bank%s (%dK)\n",maxrom+1,maxrom+1>1?"s":"",(maxrom+1)*16); + /********************************************* + ********************************************** + R O M + ********************************************** + *********************************************/ + } else if (ae->forceROM) { + unsigned char filler[16384]={0}; + int noflood=0; + + /* how many ROM? */ + for (i=maxrom=0;iio;i++) { + if (ae->orgzone[i].ibank<256 && ae->orgzone[i].ibank>maxrom) maxrom=ae->orgzone[i].ibank; + } + + for (i=0;i<=maxrom;i++) { + /* number the file */ + if (i==0 || !ae->forceROMconcat) { + if (ae->rom_name) { + sprintf(TMP_filename,"%s%d.rom",ae->rom_name,i); + } else { + sprintf(TMP_filename,"%s%d.rom",ae->outputfilename,i); + } + FileRemoveIfExists(TMP_filename); + } + + offset=65536; + endoffset=0; + for (j=0;jio;j++) { + if (ae->orgzone[j].protect) continue; /* protected zones exclusion */ + /* bank data may start anywhere (typically #0000 or #C000) */ + if (ae->orgzone[j].ibank==i && ae->orgzone[j].memstart!=ae->orgzone[j].memend) { + if (ae->orgzone[j].memstartorgzone[j].memstart; + if (ae->orgzone[j].memend>endoffset) endoffset=ae->orgzone[j].memend; + } + } + if (endoffset>offset) { + /* cannot be bigger than 16K */ + if (endoffset-offset>16384) { + rasm_printf(ae,"\nROM is too big!!!\n"); + FileRemoveIfExists(TMP_filename); + FreeAssenv(ae); + exit(ABORT_ERROR); + } + /* to avoid ROM smaller than 16K at the end of working memory */ + if (offset>49152) offset=49152; + + if (i<4 || i+4>maxrom) rasm_printf(ae,KVERBOSE"WriteROM bank %3d of %5d byte%s start at #%04X\n",i,endoffset-offset,endoffset-offset>1?"s":" ",offset); + else if (!noflood) {rasm_printf(ae,KVERBOSE"[...]\n");noflood=1;} + + FileWriteBinary(TMP_filename,(char *)(ae->mem[i]+offset),endoffset-offset); + if (endoffset-offset<16384) FileWriteBinary(TMP_filename,(char*)filler,16384-(endoffset-offset)); + if (!ae->forceROMconcat) { + FileWriteBinaryClose(TMP_filename); + } + } else { + rasm_printf(ae,KVERBOSE"WriteROM bank %3d is empty\n",i); + /* with flat output we must fill with zeroes empty banks */ + if (ae->forceROMconcat) { + FileWriteBinary(TMP_filename,(char*)filler,16384); + } + } + } + if (ae->forceROMconcat) { + FileWriteBinaryClose(TMP_filename); + } + + rasm_printf(ae,"Total %d rom%s (%dK)\n",maxrom+1,maxrom+1>1?"s":"",(maxrom+1)*16); + + /********************************************* + ********************************************** + S N A P S H O T + ********************************************** + *********************************************/ + } else if (ae->forcesnapshot) { + + if (ae->forcezx) { + unsigned char zxsnapheader[0x1A]={0}; + + if (ae->snapshot_name) { + sprintf(TMP_filename,"%s",ae->snapshot_name); + } else { + sprintf(TMP_filename,"%s.sna",ae->outputfilename); + } + FileRemoveIfExists(TMP_filename); + + /* do we have a bankset? */ + /* zx bootstrap */ + zxsnapheader[0x13]=0; /* 0:DI 4:EI */ + zxsnapheader[0x17]=ae->zxsnapshot.stack&0xFF; + zxsnapheader[0x18]=(ae->zxsnapshot.stack>>8)&0xFF; + zxsnapheader[0x19]=1; /* IM 1 */ + + //ae->zxsnapshot.stack&=0xFFFF; + ae->mem[0][ae->zxsnapshot.stack]=ae->zxsnapshot.run&0xFF; + ae->mem[0][ae->zxsnapshot.stack+1]=(ae->zxsnapshot.run>>8)&0xFF; + + rasm_printf(ae,KIO"Write 48K ZX snapshot file %s\n",TMP_filename); + + /* header */ + FileWriteBinary(TMP_filename,(char *)&zxsnapheader,27); + /* data */ + if (ae->bankset[0]) { + FileWriteBinary(TMP_filename,(char *)ae->mem[0]+16384,16384*3); + } else { + FileWriteBinary(TMP_filename,(char *)ae->mem[5],16384); + FileWriteBinary(TMP_filename,(char *)ae->mem[2],16384); + FileWriteBinary(TMP_filename,(char *)ae->mem[0],16384); + } + FileWriteBinaryClose(TMP_filename); + } else { + unsigned char packed[65536]={0}; + unsigned char *rlebank=NULL; + char ChunkName[16]; + int ChunkSize; + int bankset; + int noflood=0; + + if (!ae->flux) { + if (ae->snapshot.version==2 && ae->snapshot.CPCType>2) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: V2 snapshot cannot select a Plus model (forced to 6128)\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + if (ae->erronwarn) MaxError(ae); + } + ae->snapshot.CPCType=2; /* 6128 */ + } + + if (ae->snapshot_name) { + sprintf(TMP_filename,"%s",ae->snapshot_name); + } else { + sprintf(TMP_filename,"%s.sna",ae->outputfilename); + } + FileRemoveIfExists(TMP_filename); + } + + // we use part of SNAPSHOT code for emulator in-place output + maxrom=-1; + for (i=0;iio;i++) { + if (ae->orgzone[i].ibankorgzone[i].ibank>maxrom && ae->orgzone[i].memstart!=ae->orgzone[i].memend) { + maxrom=ae->orgzone[i].ibank; + } + } + + /* construction du SNA */ + if (ae->snapshot.version==2) { + if (maxrom>=4) { + ae->snapshot.dumpsize[0]=128; + } else if (maxrom>=0) { + ae->snapshot.dumpsize[0]=64; + } + } else { + ae->snapshot.dumpsize[0]=0; + } + + // enforce snapshot input size (if any) even we do not write everywhere in memory + if (ae->snapRAMsize-1>maxrom) maxrom=ae->snapRAMsize-1; + + if (maxrom==-1) { + rasm_printf(ae,KWARNING"Warning: No byte were written in snapshot memory\n"); + if (ae->erronwarn) MaxError(ae); + } else { + rasm_printf(ae,KIO"Write snapshot v%d file %s\n",ae->snapshot.version,TMP_filename); + + /* header */ + if (!ae->flux) FileWriteBinary(TMP_filename,(char *)&ae->snapshot,0x100); + /* write all memory crunched */ + for (i=0;i<=maxrom;i+=4) { + bankset=i>>2; + if (ae->bankset[bankset]) { + memcpy(packed,ae->mem[i],65536); + if (i<4 || i+4>maxrom) rasm_printf(ae,KVERBOSE"WriteSNA bank %2d,%d,%d,%d packed\n",i,i+1,i+2,i+3); + else if (!noflood) {rasm_printf(ae,KVERBOSE"[...]\n");noflood=1;} + } else { + memset(packed,0,65536); + for (k=0;k<4;k++) { + offset=65536; + endoffset=0; + for (j=0;jio;j++) { + if (ae->orgzone[j].protect) continue; /* protected zones exclusion */ + /* bank data may start anywhere (typically #0000 or #C000) */ + if (ae->orgzone[j].ibank==i+k && ae->orgzone[j].memstart!=ae->orgzone[j].memend) { + if (ae->orgzone[j].memstartorgzone[j].memstart; + if (ae->orgzone[j].memend>endoffset) endoffset=ae->orgzone[j].memend; + } + } + if (endoffset-offset>16384) { + rasm_printf(ae,KERROR"\nBANK is too big!!!\n"); + if (!ae->flux) { + FileWriteBinaryClose(TMP_filename); + FileRemoveIfExists(TMP_filename); + FreeAssenv(ae); + exit(ABORT_ERROR); + } //@@TODO renvoyer erreur quand meme? + } + /* banks are gathered in the 64K block */ + if (offset>0xC000) { + ChunkSize=65536-offset; + memcpy(packed+k*16384,(char*)ae->mem[i+k]+offset,ChunkSize); + } else { + memcpy(packed+k*16384,(char*)ae->mem[i+k]+offset,16384); + } + + if (endoffset>offset) { + int lm=0; + if (ae->iwnamebank[i]>0) { + lm=strlen(ae->wl[ae->iwnamebank[i]].w)-2; + } + if (i<4 || i+4>maxrom) rasm_printf(ae,KVERBOSE"WriteSNA bank %2d of %5d byte%s start at #%04X",i+k,endoffset-offset,endoffset-offset>1?"s":" ",offset); + else if (!noflood) {rasm_printf(ae,KVERBOSE"[...]\n");noflood=1;} + if (endoffset-offset>16384) { + rasm_printf(ae,KERROR"\nRAM block is too big!!!\n"); + if (!ae->flux) { + FileWriteBinaryClose(TMP_filename); + FileRemoveIfExists(TMP_filename); + FreeAssenv(ae); + exit(ABORT_ERROR); + } // @@TODO aussi + } + if (lm) { + if (i<4 || i+4>maxrom) rasm_printf(ae,KVERBOSE" (%-*.*s)\n",lm,lm,ae->wl[ae->iwnamebank[i+k]].w+1); + } else { + if (i<4 || i+4>maxrom) rasm_printf(ae,"\n"); + } + } else { + if (i<4 || i+4>maxrom) rasm_printf(ae,KVERBOSE"WriteSNA bank %2d (empty)\n",i+k); + else if (!noflood) {rasm_printf(ae,KVERBOSE"[...]\n");noflood=1;} + } + } + } + + if (ae->snapshot.version==2) { + /* snapshot v2 */ + if (!ae->flux) FileWriteBinary(TMP_filename,(char*)&packed,65536); + if (bankset) { + /* v2 snapshot is 128K maximum */ + maxrom=7; + break; + } + } else { + /* compression par défaut avec snapshot v3 */ + rlebank=EncodeSnapshotRLE(packed,&ChunkSize); + + if (bankset>=0 && bankset<=8) { + sprintf(ChunkName,"MEM%d",bankset); + } else if (bankset>8 && bankset<=0x40) { + /* extended chunk for 4M extension -> MX09 to MX40 (hexa numbered) */ + sprintf(ChunkName,"MX%02X",bankset); + } else { + MakeError(ae,"(core)",0,"internal error during snapshot write, please report (%d)\n",bankset); + } + + if (!ae->flux) { + FileWriteBinary(TMP_filename,ChunkName,4); + FileWriteBinary(TMP_filename,(char*)&ChunkSize,4); + if (rlebank!=NULL) { + FileWriteBinary(TMP_filename,(char*)rlebank,ChunkSize); + MemFree(rlebank); + } else { + // write unpacked data + FileWriteBinary(TMP_filename,(char*)&packed,ChunkSize); + } + } + } + } + + /************************************************************** + snapshot additional chunks in v3+ only + **************************************************************/ + if (!ae->flux && ae->snapshot.version>=3) { + /* export breakpoint */ + if (ae->export_snabrk) { + /* BRKS chunk for Winape emulator (unofficial) + + 2 bytes - address + 1 byte - 0=base 64K / 1=extended + 2 bytes - condition (zeroed) + */ + struct s_breakpoint breakpoint={0}; + unsigned char *brkschunk=NULL; + unsigned int idx=8; + + /* add labels and local labels to breakpoint pool (if any) */ + for (i=0;iil;i++) { + if (!ae->label[i].name) { + if (strncmp(ae->wl[ae->label[i].iw].w,"BRK",3)==0 || strncmp(ae->wl[ae->label[i].iw].w,"@BRK",4)==0 || strstr(ae->wl[ae->label[i].iw].w,".BRK")!=NULL) { + breakpoint.address=ae->label[i].ptr; + if (ae->label[i].ibank>3) breakpoint.bank=1; else breakpoint.bank=0; + ObjectArrayAddDynamicValueConcat((void **)&ae->breakpoint,&ae->ibreakpoint,&ae->maxbreakpoint,&breakpoint,sizeof(struct s_breakpoint)); + } + } else { + if (strncmp(ae->label[i].name,"BRK",3)==0 || strncmp(ae->label[i].name,"@BRK",4)==0 || strstr(ae->label[i].name,".BRK")) { + breakpoint.address=ae->label[i].ptr; + if (ae->label[i].ibank>3) breakpoint.bank=1; else breakpoint.bank=0; + ObjectArrayAddDynamicValueConcat((void **)&ae->breakpoint,&ae->ibreakpoint,&ae->maxbreakpoint,&breakpoint,sizeof(struct s_breakpoint)); + } + } + } + + brkschunk=MemMalloc(ae->ibreakpoint*5+8); + strcpy((char *)brkschunk,"BRKS"); + + for (i=0;iibreakpoint;i++) { + brkschunk[idx++]=ae->breakpoint[i].address&0xFF; + brkschunk[idx++]=(ae->breakpoint[i].address&0xFF00)/256; + brkschunk[idx++]=ae->breakpoint[i].bank; + brkschunk[idx++]=0; + brkschunk[idx++]=0; + } + + idx-=8; + brkschunk[4]=idx&0xFF; + brkschunk[5]=(idx>>8)&0xFF; + brkschunk[6]=(idx>>16)&0xFF; + brkschunk[7]=(idx>>24)&0xFF; + FileWriteBinary(TMP_filename,(char*)brkschunk,idx+8); // 8 bytes for the chunk header + MemFree(brkschunk); + + + /* BRKC chunk for ACE emulator + minimal integration + */ + brkschunk=MemMalloc(ae->ibreakpoint*256); + strcpy((char *)brkschunk,"BRKC"); + idx=8; + + for (i=0;iibreakpoint;i++) { + brkschunk[idx++]=0; /* 0:Execution */ + brkschunk[idx++]=0; + brkschunk[idx++]=0; + brkschunk[idx++]=0; + brkschunk[idx++]=ae->breakpoint[i].address&0xFF; + brkschunk[idx++]=(ae->breakpoint[i].address&0xFF00)/256; + for (j=0;j<2+1+1+2+4+128;j++) { + brkschunk[idx++]=0; + } + sprintf((char *)brkschunk+idx,"breakpoint%d",i); /* breakpoint user name? */ + idx+=64+8; + } + idx-=8; + brkschunk[4]=idx&0xFF; + brkschunk[5]=(idx>>8)&0xFF; + brkschunk[6]=(idx>>16)&0xFF; + brkschunk[7]=(idx>>24)&0xFF; + FileWriteBinary(TMP_filename,(char *)brkschunk,idx+8); // 8 bytes for the chunk header + MemFree(brkschunk); + } + /* export optionnel des symboles */ + if (ae->export_sna) { + /* SYMB chunk for ACE emulator + + 1 byte - name size + n bytes - name (without 0 to end the string) + 6 bytes - reserved for future use + 2 bytes - shitty big endian address for the symbol + */ + + unsigned char *symbchunk=NULL; + unsigned int idx=8; + int symbol_len; + + symbchunk=MemMalloc(8+ae->il*(1+255+6+2)); + strcpy((char *)symbchunk,"SYMB"); + + for (i=0;iil;i++) { + if (!ae->label[i].name) { + symbol_len=strlen(ae->wl[ae->label[i].iw].w); + if (symbol_len>255) symbol_len=255; + symbchunk[idx++]=symbol_len; + memcpy(symbchunk+idx,ae->wl[ae->label[i].iw].w,symbol_len); + idx+=symbol_len; + memset(symbchunk+idx,0,6); + idx+=6; + symbchunk[idx++]=(ae->label[i].ptr&0xFF00)/256; + symbchunk[idx++]=ae->label[i].ptr&0xFF; + } else { + if (ae->export_local || !ae->label[i].local) { + symbol_len=strlen(ae->label[i].name); + if (symbol_len>255) symbol_len=255; + symbchunk[idx++]=symbol_len; + memcpy(symbchunk+idx,ae->label[i].name,symbol_len); + idx+=symbol_len; + memset(symbchunk+idx,0,6); + idx+=6; + symbchunk[idx++]=(ae->label[i].ptr&0xFF00)/256; + symbchunk[idx++]=ae->label[i].ptr&0xFF; + } + } + } + if (ae->export_var) { + unsigned char *subchunk=NULL; + int retidx=0; + /* var are part of fast tree search structure */ + subchunk=SnapshotDicoTree(ae,&retidx); + if (retidx) { + symbchunk=MemRealloc(symbchunk,idx+retidx); + memcpy(symbchunk+idx,subchunk,retidx); + idx+=retidx; + SnapshotDicoInsert("FREE",0,&retidx); + } + } + if (ae->export_equ) { + symbchunk=MemRealloc(symbchunk,idx+ae->ialias*(1+255+6+2)); + + for (i=0;iialias;i++) { + int tmpptr; + symbol_len=strlen(ae->alias[i].alias); + if (symbol_len>255) symbol_len=255; + symbchunk[idx++]=symbol_len; + memcpy(symbchunk+idx,ae->alias[i].alias,symbol_len); + idx+=symbol_len; + memset(symbchunk+idx,0,6); + idx+=6; + tmpptr=RoundComputeExpression(ae,ae->alias[i].translation,0,0,0); + symbchunk[idx++]=(tmpptr&0xFF00)/256; + symbchunk[idx++]=tmpptr&0xFF; + } + } + idx-=8; + symbchunk[4]=idx&0xFF; + symbchunk[5]=(idx>>8)&0xFF; + symbchunk[6]=(idx>>16)&0xFF; + symbchunk[7]=(idx>>24)&0xFF; + FileWriteBinary(TMP_filename,(char*)symbchunk,idx+8); // 8 bytes for the chunk header + } + } else { + if (ae->export_snabrk) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"Warning: breakpoint export is not supported with snapshot version 2\n"); + if (ae->erronwarn) MaxError(ae); + } + } + if (ae->export_sna) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"Warning: symbol export is not supported with snapshot version 2\n"); + if (ae->erronwarn) MaxError(ae); + } + } + } + + if (!ae->flux) FileWriteBinaryClose(TMP_filename); + maxrom=(maxrom>>2)*4+4; + rasm_printf(ae,KAYGREEN"Total %d bank%s (%dK)\n",maxrom,maxrom>1?"s":"",(maxrom)*16); + } + } + /********************************************* + ********************************************** + B I N A R Y F I L E + ********************************************** + *********************************************/ + } else { + int lastspaceid=-1; + + if (ae->binary_name) { + sprintf(TMP_filename,"%s",ae->binary_name); + } else { + sprintf(TMP_filename,"%s.bin",ae->outputfilename); + } + FileRemoveIfExists(TMP_filename); + + /* en mode binaire classique on va recherche le dernier espace mémoire dans lequel on a travaillé qui n'est pas en 'nocode' */ + for (i=0;iio;i++) { + /* uniquement si le ORG a ete suivi d'ecriture */ + if (ae->orgzone[i].memstart!=ae->orgzone[i].memend && ae->orgzone[i].nocode!=1) { + lastspaceid=ae->orgzone[i].ibank; + } + } + if (lastspaceid!=-1) { + for (i=0;iio;i++) { + if (ae->orgzone[i].protect) continue; /* protected zones exclusion */ + /* uniquement si le ORG a ete suivi d'ecriture et n'est pas en 'nocode' */ + if (ae->orgzone[i].ibank==lastspaceid && ae->orgzone[i].memstart!=ae->orgzone[i].memend && ae->orgzone[i].nocode!=1) { + if (ae->orgzone[i].memstartorgzone[i].memstart; + if (ae->orgzone[i].memend>maxmem) maxmem=ae->orgzone[i].memend; + } + } + } + if (maxmem-minmem<=0) { + if (!ae->stop) { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"Warning: Not a single byte to output\n"); + if (ae->erronwarn) MaxError(ae); + } + } + if (ae->flux) { + *lenout=0; + } + } else { + if (!ae->flux) { + /*************************************************************** + * T A P E o u t p u t * + ***************************************************************/ + if (ae->forcetape) { + int run; + if (ae->tape_name) { + sprintf(TMP_filename,"%s",ae->tape_name); + } else { + sprintf(TMP_filename,"%s.cdt",ae->outputfilename); + } + run=ae->snapshot.registers.LPC+(ae->snapshot.registers.HPC<<8); + if (run<0x100) run=minmem; + __output_CDT(ae,TMP_filename,"TAPE.BIN",(char*)ae->mem[lastspaceid]+minmem,maxmem-minmem,minmem,run); + } else { + /*************************************************************** + * O B J o u t p u t * + ***************************************************************/ + if (ae->buildobj) { + struct s_label *curlabel; + char objtmp[1024]; + int iex,jex; + + sprintf(TMP_filename,"%s.obj",ae->outputfilename); + FileRemoveIfExists(TMP_filename); + rasm_printf(ae,KIO"Write OBJ file %s\n",TMP_filename,maxmem-minmem); + + for (i=0;inprocedurename;i++) { + curlabel=SearchLabel(ae,ae->procedurename[i],GetCRC(ae->procedurename[i])); + if (!curlabel) { + rasm_printf(ae,KERROR" INTERNAL ERROR: procedure [%s] not found in label pool\n"); + MaxError(ae); + } else { + strcpy(objtmp,"PROCEDURE "); + FileWriteBinary(TMP_filename,(char *)objtmp,strlen(objtmp)); + FileWriteBinary(TMP_filename,(char *)ae->procedurename[i],strlen(ae->procedurename[i])); + sprintf(objtmp," 0x%04X\n",curlabel->ptr); + FileWriteBinary(TMP_filename,(char *)objtmp,strlen(objtmp)); + } + } + for (i=0;inexternal;i++) { + for (j=0;jexternal[i].nmapping;j++) { + strcpy(objtmp,"EXTERNAL "); + FileWriteBinary(TMP_filename,(char *)objtmp,strlen(objtmp)); + FileWriteBinary(TMP_filename,(char *)ae->external[i].name,strlen(ae->external[i].name)); + sprintf(objtmp," 0x%04X %d\n",ae->external[i].mapping[j].ptr,ae->external[i].mapping[j].size); + FileWriteBinary(TMP_filename,(char *)objtmp,strlen(objtmp)); + } + } + for (i=0;inrelocation;i++) { + if (ae->relocation[i].value>=minmem && ae->relocation[i].valuerelocation[i].ptr); + FileWriteBinary(TMP_filename,(char *)objtmp,strlen(objtmp)); + } + } + for (i=0;inrelocation;i++) { + if (ae->relocation[i].value>=minmem && ae->relocation[i].valuerelocation[i].ptr); + FileWriteBinary(TMP_filename,(char *)objtmp,strlen(objtmp)); + } + } + sprintf(objtmp,"DATA START=0x%04X LEN=0x%04X\n",minmem,maxmem-minmem); + FileWriteBinary(TMP_filename,(char *)objtmp,strlen(objtmp)); + j=0; + for (i=minmem;imem[lastspaceid][i]); + FileWriteBinary(TMP_filename,(char *)objtmp,strlen(objtmp)); + j++; + if (j==16) { + strcpy(objtmp,"\n"); + FileWriteBinary(TMP_filename,(char *)objtmp,strlen(objtmp)); + j=0; + } + } + strcpy(objtmp,"\n"); + FileWriteBinary(TMP_filename,(char *)objtmp,strlen(objtmp)); + FileWriteBinaryClose(TMP_filename); + } else { + /*************************************************************** + * F I L E o u t p u t * + ***************************************************************/ + rasm_printf(ae,KIO"Write binary file %s (%d byte%s)",TMP_filename,maxmem-minmem,maxmem-minmem>1?"s":""); + if (ae->amsdos) { + AmsdosHeader=MakeAMSDOSHeader(minmem,minmem,maxmem,TMP_filename); //@@TODO + FileWriteBinary(TMP_filename,(char *)AmsdosHeader,128); + rasm_printf(ae," (automatic Amsdos header)\n"); + } else { + rasm_printf(ae,"\n"); + } + if (maxmem-minmem>0) { + FileWriteBinary(TMP_filename,(char*)ae->mem[lastspaceid]+minmem,maxmem-minmem); + FileWriteBinaryClose(TMP_filename); + } else { + if (ae->amsdos) { + FileWriteBinaryClose(TMP_filename); + } + } + } + } + } else { + if (dataout) { + *dataout=MemMalloc(maxmem-minmem+1); + memcpy(*dataout,ae->mem[lastspaceid]+minmem,maxmem-minmem); + *lenout=maxmem-minmem; + } + } + } + } + } + /******************************** + ********************************* + U N U S E D W A R N I N G + ********************************* + ********************************/ + if (ae->warn_unused) { + for (i=0;iialias;i++) { + if (strcmp(ae->alias[i].alias,"IX") && strcmp(ae->alias[i].alias,"IY")) { + if (!ae->alias[i].used) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: alias %s declared but not used\n",ae->filename[ae->wl[ae->alias[i].iw].ifile],ae->wl[ae->alias[i].iw].l,ae->alias[i].alias); + if (ae->erronwarn) MaxError(ae); + } + } + } + WarnLabelTree(ae); + WarnDicoTree(ae); + } + + /**************************** + ***************************** + S Y M B O L E X P O R T + ***************************** + ****************************/ + if (ae->export_sym && !ae->export_sna) { + char *SymbolFileName; + SymbolFileName=MemMalloc(PATH_MAX); + +#define MAKE_SYMBOL_NAME if (ae->symbol_name) {sprintf(TMP_filename,"%s",ae->symbol_name);} else {sprintf(TMP_filename,"%s.sym",ae->outputfilename);} + + MAKE_SYMBOL_NAME + FileRemoveIfExists(TMP_filename); + + if (ae->export_multisym) { + /* multi-remove before writes */ + for (i=0;inbbank;i++) { + if (ae->symbol_name) { + sprintf(TMP_filename,"%s.bank%d",ae->symbol_name,i); + } else { + sprintf(TMP_filename,"%s.sym.bank%d",ae->outputfilename,i); + } + FileRemoveIfExists(TMP_filename); + } + rasm_printf(ae,KIO"Write symbol files %s.bank*\n",TMP_filename); + } else { + rasm_printf(ae,KIO"Write symbol file %s\n",TMP_filename); + } + + /**************************** + case export hack + ****************************/ + if (ae->enforce_symbol_case) { + char *casefound; + int ilocal=0; + + for (i=0;iil;i++) { + if (ae->label[i].autorise_export) { + if (!ae->label[i].name) { + if ((casefound=_internal_stristr(ae->rawfile[ae->label[i].fileidx],ae->rawlen[ae->label[i].fileidx],ae->wl[ae->label[i].iw].w))!=NULL) { + memcpy(ae->wl[ae->label[i].iw].w,casefound,strlen(ae->wl[ae->label[i].iw].w)); + } + } else if (ae->export_local || !ae->label[i].local) { + char splitlabel[256]; + char casecharbackup; + int caseidx; + int istart,iend,ilen,isplit,icopy; + + ilen=strlen(ae->label[i].name); + + if (ae->label[i].name[0]=='@') { + // remove radix + while (ae->label[i].name[ilen]!='R') ilen--; + ae->label[i].name[ilen]=0; + } + + iend=0; + do { + istart=iend; + while (!AutomateCharStop[ae->label[i].name[istart]]) istart++; + if (istart>=ilen) break; + + iend=istart; + while (AutomateChar[ae->label[i].name[iend]]) iend++; + + isplit=0; + icopy=istart; + while (icopylabel[i].name[icopy++]; + splitlabel[isplit]=0; + + if (isplit>1) { + casefound=_internal_stristr(ae->rawfile[ae->label[i].fileidx],ae->rawlen[ae->label[i].fileidx],splitlabel); + if (casefound) { + memcpy(ae->label[i].name+istart,casefound,isplit); + } + } + } while (istartlabel[i].name[0]=='@') { + // put simplified radix back + ae->label[i].name[ilen]='_'; + sprintf(ae->label[i].name+ilen+1,"%x",ilocal++); + } + } + } + } + // translate alias only if there are exported + if (ae->export_equ) { + for (i=0;iialias;i++) { + if ((casefound=_internal_stristr(ae->rawfile[ae->wl[ae->alias[i].iw].ifile],ae->rawlen[ae->wl[ae->alias[i].iw].ifile],ae->alias[i].alias))!=NULL) { + memcpy(ae->alias[i].alias,casefound,strlen(ae->alias[i].alias)); + } + } + } + } + + switch (ae->export_sym) { + case 5: + /* ZX export */ + for (i=0;iil;i++) { + if (ae->label[i].autorise_export) { + if (ae->export_multisym) { + if (ae->symbol_name) { + sprintf(TMP_filename,"%s.bank%d",ae->symbol_name,ae->label[i].ibank); + } else { + sprintf(TMP_filename,"%s.sym.bank%d",ae->outputfilename,ae->label[i].ibank); + } + } + + if (!ae->label[i].name) { + sprintf(symbol_line,"%d:%04X %s\n",ae->label[i].ibank,ae->label[i].ptr,ae->wl[ae->label[i].iw].w); + FileWriteLine(TMP_filename,symbol_line); + } else { + if (ae->export_local || !ae->label[i].local) { + sprintf(symbol_line,"%d:%04X %s\n",ae->label[i].ibank,ae->label[i].ptr,ae->label[i].name); + FileWriteLine(TMP_filename,symbol_line); + } + } + } + } + FileWriteLineClose(TMP_filename); + MAKE_SYMBOL_NAME + if (ae->export_var) { + /* var are part of fast tree search structure */ + ExportDicoTree(ae,TMP_filename,"%s %04X"); + } + if (ae->export_equ) { + for (i=0;iialias;i++) { + if (strcmp(ae->alias[i].alias,"IX") && strcmp(ae->alias[i].alias,"IY")) { + sprintf(symbol_line,"%04X %s\n",RoundComputeExpression(ae,ae->alias[i].translation,0,-ae->alias[i].iw,0),ae->alias[i].alias); + FileWriteLine(TMP_filename,symbol_line); + } + } + } + break; + case 4: + /* flexible */ + for (i=0;iil;i++) { + if (ae->label[i].autorise_export) { + if (ae->export_multisym) { + if (ae->symbol_name) { + sprintf(TMP_filename,"%s.bank%d",ae->symbol_name,ae->label[i].ibank); + } else { + sprintf(TMP_filename,"%s.sym.bank%d",ae->outputfilename,ae->label[i].ibank); + } + } + + if (!ae->label[i].name) { + sprintf(symbol_line,ae->flexible_export,ae->wl[ae->label[i].iw].w,ae->label[i].ptr); + FileWriteLine(TMP_filename,symbol_line); + } else { + if (ae->export_local || !ae->label[i].local) { + sprintf(symbol_line,ae->flexible_export,ae->label[i].name,ae->label[i].ptr); + FileWriteLine(TMP_filename,symbol_line); + } + } + } + } + MAKE_SYMBOL_NAME + if (ae->export_var) { + /* var are part of fast tree search structure */ + ExportDicoTree(ae,TMP_filename,ae->flexible_export); + } + if (ae->export_equ) { + for (i=0;iialias;i++) { + if (strcmp(ae->alias[i].alias,"IX") && strcmp(ae->alias[i].alias,"IY")) { + sprintf(symbol_line,ae->flexible_export,ae->alias[i].alias,RoundComputeExpression(ae,ae->alias[i].translation,0,-ae->alias[i].iw,0)); + FileWriteLine(TMP_filename,symbol_line); + } + } + } + FileWriteLineClose(TMP_filename); + break; + case 3: + /* Winape */ + for (i=0;iil;i++) { + if (ae->label[i].autorise_export) { + if (ae->export_multisym) { + if (ae->symbol_name) { + sprintf(TMP_filename,"%s.bank%d",ae->symbol_name,ae->label[i].ibank); + } else { + sprintf(TMP_filename,"%s.sym.bank%d",ae->outputfilename,ae->label[i].ibank); + } + } + if (!ae->label[i].name) { + sprintf(symbol_line,"%s #%04X\n",ae->wl[ae->label[i].iw].w,ae->label[i].ptr); + FileWriteLine(TMP_filename,symbol_line); + } else { + if (ae->export_local || !ae->label[i].local) { + sprintf(symbol_line,"%s #%04X\n",ae->label[i].name,ae->label[i].ptr); + FileWriteLine(TMP_filename,symbol_line); + } + } + } + } + MAKE_SYMBOL_NAME + if (ae->export_var) { + /* var are part of fast tree search structure */ + ExportDicoTree(ae,TMP_filename,"%s #%04X\n"); + } + if (ae->export_equ) { + for (i=0;iialias;i++) { + if (strcmp(ae->alias[i].alias,"IX") && strcmp(ae->alias[i].alias,"IY")) { + sprintf(symbol_line,"%s #%04X\n",ae->alias[i].alias,RoundComputeExpression(ae,ae->alias[i].translation,0,-ae->alias[i].iw,0)); + FileWriteLine(TMP_filename,symbol_line); + } + } + } + FileWriteLineClose(TMP_filename); + break; + case 2: + /* pasmo */ + for (i=0;iil;i++) { + if (ae->label[i].autorise_export) { + if (ae->export_multisym) { + if (ae->symbol_name) { + sprintf(TMP_filename,"%s.bank%d",ae->symbol_name,ae->label[i].ibank); + } else { + sprintf(TMP_filename,"%s.sym.bank%d",ae->outputfilename,ae->label[i].ibank); + } + } + if (!ae->label[i].name) { + sprintf(symbol_line,"%s EQU 0%04XH\n",ae->wl[ae->label[i].iw].w,ae->label[i].ptr); + FileWriteLine(TMP_filename,symbol_line); + } else { + if (ae->export_local || !ae->label[i].local) { + sprintf(symbol_line,"%s EQU 0%04XH\n",ae->label[i].name,ae->label[i].ptr); + FileWriteLine(TMP_filename,symbol_line); + } + } + } + } + MAKE_SYMBOL_NAME + if (ae->export_var) { + /* var are part of fast tree search structure */ + ExportDicoTree(ae,TMP_filename,"%s EQU 0%04XH\n"); + } + if (ae->export_equ) { + for (i=0;iialias;i++) { + if (strcmp(ae->alias[i].alias,"IX") && strcmp(ae->alias[i].alias,"IY")) { + sprintf(symbol_line,"%s EQU 0%04XH\n",ae->alias[i].alias,RoundComputeExpression(ae,ae->alias[i].translation,0,-ae->alias[i].iw,0)); + FileWriteLine(TMP_filename,symbol_line); + } + } + } + FileWriteLineClose(TMP_filename); + break; + case 1: + /* Rasm */ + for (i=0;iil;i++) { + if (ae->label[i].autorise_export) { + if (ae->export_multisym) { + if (ae->symbol_name) { + sprintf(TMP_filename,"%s.bank%d",ae->symbol_name,ae->label[i].ibank); + } else { + sprintf(TMP_filename,"%s.sym.bank%d",ae->outputfilename,ae->label[i].ibank); + } + } + if (!ae->label[i].name) { + sprintf(symbol_line,"%s #%X B%d\n",ae->wl[ae->label[i].iw].w,ae->label[i].ptr,ae->label[i].ibank>31?0:ae->label[i].ibank); + FileWriteLine(TMP_filename,symbol_line); + } else { + if (ae->export_local || !ae->label[i].local) { + sprintf(symbol_line,"%s #%X B%d\n",ae->label[i].name,ae->label[i].ptr,ae->label[i].ibank>31?0:ae->label[i].ibank); + FileWriteLine(TMP_filename,symbol_line); + } + } + } + } + MAKE_SYMBOL_NAME + if (ae->export_var) { + /* var are part of fast tree search structure */ + ExportDicoTree(ae,TMP_filename,"%s #%X B0\n"); + } + if (ae->export_equ) { + for (i=0;iialias;i++) { + if (strcmp(ae->alias[i].alias,"IX") && strcmp(ae->alias[i].alias,"IY") && ae->alias[i].autorise_export) { + sprintf(symbol_line,"%s #%X B0\n",ae->alias[i].alias,RoundComputeExpression(ae,ae->alias[i].translation,0,-ae->alias[i].iw,0)); + FileWriteLine(TMP_filename,symbol_line); + } + } + } + FileWriteLineClose(TMP_filename); + break; + case 0: + default:break; + } + MemFree(SymbolFileName); + } + /********************************* + ********************************** + B R E A K P O I N T S + ********************************** + *********************************/ + if (ae->export_brk) { + struct s_breakpoint breakpoint={0}; + + if (ae->breakpoint_name) { + sprintf(TMP_filename,"%s",ae->breakpoint_name); + } else { + sprintf(TMP_filename,"%s.brk",ae->outputfilename); + } + FileRemoveIfExists(TMP_filename); + + /* add labels and local labels to breakpoint pool (if any) */ + for (i=0;iil;i++) { + if (!ae->label[i].name) { + if (strncmp(ae->wl[ae->label[i].iw].w,"BRK",3)==0 || strncmp(ae->wl[ae->label[i].iw].w,"@BRK",4)==0 || strstr(ae->wl[ae->label[i].iw].w,".BRK")) { + breakpoint.address=ae->label[i].ptr; + if (ae->label[i].ibank>3) breakpoint.bank=1; else breakpoint.bank=0; + ObjectArrayAddDynamicValueConcat((void **)&ae->breakpoint,&ae->ibreakpoint,&ae->maxbreakpoint,&breakpoint,sizeof(struct s_breakpoint)); + } + } else { + if (strncmp(ae->label[i].name,"BRK",3)==0 || strncmp(ae->label[i].name,"@BRK",4)==0 || strstr(ae->label[i].name,".BRK")) { + breakpoint.address=ae->label[i].ptr; + if (ae->label[i].ibank>3) breakpoint.bank=1; else breakpoint.bank=0; + ObjectArrayAddDynamicValueConcat((void **)&ae->breakpoint,&ae->ibreakpoint,&ae->maxbreakpoint,&breakpoint,sizeof(struct s_breakpoint)); + } + } + } + + if (ae->ibreakpoint) { + rasm_printf(ae,KIO"Write breakpoint file %s\n",TMP_filename); + for (i=0;iibreakpoint;i++) { + sprintf(symbol_line,"#%04X\n",ae->breakpoint[i].address); + FileWriteLine(TMP_filename,symbol_line); + } + FileWriteLineClose(TMP_filename); + } else { + if (!ae->nowarning) { + rasm_printf(ae,KWARNING"Warning: no breakpoint to output\n",TMP_filename); + if (ae->erronwarn) MaxError(ae); + /* empty file */ + FileTruncate(TMP_filename); + } + } + } + /********************************* + ********************************** + DEBUG INFO + ********************************** + *********************************/ + if (ae->retdebug) { + if (ae->rundefined) { + ae->debug.run=ae->snapshot.registers.LPC+(ae->snapshot.registers.HPC<<8); + } else { + ae->debug.run=-1; + } + ae->debug.start=minmem; + } + + } else { + if (!ae->dependencies) rasm_printf(ae,KERROR"%d error%s\n",ae->nberr,ae->nberr>1?"s":""); + } +#if TRACE_ASSEMBLE +printf("dependencies\n"); +#endif +/******************************************************************************************* + E X P O R T D E P E N D E N C I E S +*******************************************************************************************/ + if (ae->dependencies) { + int trigdep=0; + + /* depends ALL */ + if (ae->outputfilename && strcmp(ae->outputfilename,"rasmoutput")) { + trigdep=1; + printf("%s",ae->outputfilename); + if (ae->dependencies==E_DEPENDENCIES_MAKE) printf(" "); else printf("\n"); + } + for (i=1;iifile;i++) { + trigdep=1; + SimplifyPath(ae->filename[i]); + printf("%s",ae->filename[i]); + if (ae->dependencies==E_DEPENDENCIES_MAKE) printf(" "); else printf("\n"); + } + for (i=0;iih;i++) { + trigdep=1; + SimplifyPath(ae->hexbin[i].filename); + printf("%s",ae->hexbin[i].filename); + if (ae->dependencies==E_DEPENDENCIES_MAKE) printf(" "); else printf("\n"); + } + if (ae->dependencies==E_DEPENDENCIES_MAKE && trigdep) printf("\n"); + } + +/******************************************************************************************* + V E R B O S E S H I T +*******************************************************************************************/ + if (ae->display_stats) { + int parsed_size=0; + rasm_printf(ae,KVERBOSE"------ statistics ------------------\n"); + rasm_printf(ae,KVERBOSE"%d file%s\n",ae->ifile,ae->ifile>1?"s":""); + rasm_printf(ae,KVERBOSE"%d binary include%s\n",ae->ih,ae->ih>1?"s":""); + rasm_printf(ae,KVERBOSE"%d word%s\n",ae->nbword-1,ae->nbword>2?"s":""); + rasm_printf(ae,KVERBOSE"%d label%s\n",ae->il,ae->il>1?"s":""); + rasm_printf(ae,KVERBOSE"%d struct%s\n",ae->irasmstruct,ae->irasmstruct>1?"s":""); + rasm_printf(ae,KVERBOSE"%d var%s\n",ae->idic,ae->idic>1?"s":""); + rasm_printf(ae,KVERBOSE"%d expression%s\n",ae->ie,ae->ie>1?"s":""); + rasm_printf(ae,KVERBOSE"%d macro%s\n",ae->imacro,ae->imacro>1?"s":""); + rasm_printf(ae,KVERBOSE"%d alias%s\n",ae->ialias,ae->ialias>1?"s":""); + rasm_printf(ae,KVERBOSE"%d ORG zone%s\n",ae->io-1,ae->io>2?"s":""); + rasm_printf(ae,KVERBOSE"%d virtual space%s\n",ae->nbbank,ae->nbbank>1?"s":""); + rasm_printf(ae,KVERBOSE"\n"); + for (i=0;inbword;i++) parsed_size+=strlen(ae->wl[i].w); + rasm_printf(ae,KVERBOSE"%d byte%s of pure code\n",parsed_size,parsed_size>1?"s":""); + } +/******************************************************************************************* + C L E A N U P +*******************************************************************************************/ +#if TRACE_ASSEMBLE +printf("cleanup\n"); +#endif +#if TRACE_GENERALE +printf("-cleanup\n"); +#endif + if (TMP_filename) MemFree(TMP_filename); + if (ae->nberr) { + ok=-1; + if (ae->flux && *dataout) { + MemFree(*dataout); + *dataout=NULL; + } + if (lenout) *lenout=0; + } else { + ok=0; + } + + /********************************************************************* + * + * assembling into emulator memory + * + * ******************************************************************/ + /* get back memory if requested */ + if (ae->retdebug && ae->debug.emuram && ae->debug.lenram) { + int ramidx,ramend,maxbank; + + maxbank=ae->debug.lenram>>14; + ramidx=0; + for (i=0;ibankset[i>>2]) { + if (ramidx+65536<=ae->debug.lenram) ramend=65536; else ramend=ae->debug.lenram-ramidx; + for (j=0;jdebug.emuram[ramidx++]=ae->mem[i][j]; + } + } else { + printf("@@@ simple banking unsupported => todo\n"); + /* unsupported now => @@TODO */ + } + } + } + + FreeAssenv(ae); +#if TRACE_ASSEMBLE +printf("end of assembling\n"); +printf("-end ok=%d\n",ok); +#endif +#if TRACE_GENERALE +printf("-end ok=%d\n",ok); +#endif + return ok; +} + + +void EarlyPrepSrc(struct s_assenv *ae, char **listing, char *filename) { + int l,idx,c,quote_type=0; + int mlc_start,mlc_idx; + + /* virer les commentaires en ;, // mais aussi multi-lignes et convertir les decalages, passer les chars en upper case */ + l=idx=0; + while (listing[l]) { + c=listing[l][idx++]; + + if (!c) { + l++; + idx=0; + continue; + } else { + if (!quote_type) { + + /* upper case */ + if (c>='a' && c<='z') { + listing[l][idx-1]=c=c-'a'+'A'; + } + + if (c=='\'') { + if (idx>2 && strncmp(&listing[l][idx-3],"AF'",3)==0) { + /* il ne faut rien faire */ + } else { + quote_type=c; + } + } else if (c=='"') { + quote_type=c; + } else if (c==';' || (c=='/' && listing[l][idx]=='/')) { + idx--; + while (listing[l][idx] && listing[l][idx]!=0x0D && listing[l][idx]!=0x0A) listing[l][idx++]=':'; + idx--; + } else if (c=='>' && listing[l][idx]=='>' && !quote_type) { + listing[l][idx-1]=']'; + listing[l][idx++]=' '; + continue; + } else if (c=='<' && listing[l][idx]=='<' && !quote_type) { + listing[l][idx-1]='['; + listing[l][idx++]=' '; + continue; + } else if (c=='/' && listing[l][idx]=='*' && !quote_type) { + /* multi-line comment */ + mlc_start=l; + mlc_idx=idx-1; + idx++; + while (1) { + c=listing[l][idx++]; + if (!c) { + idx=0; + l++; + if (!listing[l]) { + MakeError(ae,filename,l+1,"opened comment to the end of the file\n"); + return; + } + } else if (c=='*' && listing[l][idx]=='/') { + idx++; + break; + } + } + /* merge */ + if (mlc_start==l) { + /* on the same line */ + while (mlc_idx0) + while (l>=0) { + /* patch merge line with '\' only outside quotes */ + idx=strlen(listing[l])-1; + + if (idx>0) { + while (idx && (listing[l][idx]==' ' || listing[l][idx]==0x0D || listing[l][idx]==0x0A || listing[l][idx]==0x0B)) { + idx--; + } + + if (listing[l][idx]=='\\') { + /* fusion avec la ligne suivante qui est obligatoirement présente */ + listing[l]=MemRealloc(listing[l],strlen(listing[l])+strlen(listing[l+1])+1); + strcpy(listing[l]+idx,listing[l+1]); + strcpy(listing[l+1],""); + } + } + l--; + } +} + +void PreProcessingSplitListing(struct s_listing **listing, int *il, int *ml, int idx, int end, int start) +{ + #undef FUNC + #define FUNC "PreProcessingSplitListing" + + struct s_listing curlisting={0}; + + /* split current line because there will be "before" include and "after include" line */ + ObjectArrayAddDynamicValueConcat((void**)listing,il,ml,&curlisting,sizeof(curlisting)); + MemMove(&((*listing)[idx+2]),&((*listing)[idx+1]),(*il-idx-2)*sizeof(struct s_listing)); + (*listing)[idx+1].ifile=(*listing)[idx].ifile; + (*listing)[idx+1].iline=(*listing)[idx].iline; + if ((*listing)[idx].listing[start]) { + (*listing)[idx+1].listing=TxtStrDup((*listing)[idx].listing+start); + } else { + (*listing)[idx+1].listing=TxtStrDup(";"); + } + strcpy((*listing)[idx].listing+end,":"); +} + +void PreProcessingInsertListing(struct s_listing **reflisting, int *il, int *ml, int idx, char **zelines, int ifile) +{ + #undef FUNC + #define FUNC "PreProcessingSplitListing" + + struct s_listing *listing; + int nbinsert,li,bil; + for (li=nbinsert=0;zelines[li];li++) nbinsert++; + bil=*il; + if (*il+nbinsert>=*ml) { + *il=*ml=*il+nbinsert; + *reflisting=MemRealloc(*reflisting,sizeof(struct s_listing)*(*ml)); + } else { + *il=*il+nbinsert; + } + listing=*reflisting; + MemMove(&listing[idx+1+nbinsert],&listing[idx+1],(bil-idx-1)*sizeof(struct s_listing)); + + for (li=0;zelines[li];li++) { + listing[idx+1+li].ifile=ifile; + listing[idx+1+li].iline=li+1; + listing[idx+1+li].listing=zelines[li]; + } +} + +int cmpkeyword(const void * a, const void * b) +{ + struct s_asm_keyword *sa,*sb; + sa=(struct s_asm_keyword *)a; + sb=(struct s_asm_keyword *)b; + return strcmp(sa->mnemo,sb->mnemo); +} + +struct s_assenv *PreProcessing(char *filename, int flux, const char *datain, int datalen, struct s_parameter *param) +{ + #undef FUNC + #define FUNC "PreProcessing" + + #define CharWord "@ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.=_($)][+-*/^%#|&'\"\\m}{[]" + + struct s_assenv *ae=NULL; + struct s_wordlist curw={0}; + struct s_wordlist *wordlist=NULL; + int nbword=0,maxword=0; + char **zelines=NULL; + + char *filename_toread; + + struct s_macro_fast *MacroFast=NULL; + int idxmacrofast=0,maxmacrofast=0; + + struct s_listing *listing=NULL; + struct s_listing curlisting; + int ilisting=0,maxlisting=0; + + char **listing_include=NULL; + int i,j,l=0,idx=0,c=0,li,le; + char Automate[256]={0}; + char AutomatePrepro[256]={0}; + struct s_hexbin curhexbin; + char *newlistingline=NULL; + struct s_label curlabel={0}; + char *labelsep1; + char **labelines=NULL; + /* state machine buffer */ + unsigned char *mem=NULL; + char *w=NULL,*wtmp=NULL; + int lw=0,mw=256; + char *bval=NULL; + int ival=0,sval=256; + char *qval=NULL; + int iqval=0,sqval=256; + struct s_repeat_index *TABrindex=NULL; + struct s_repeat_index *TABwindex=NULL; + struct s_repeat_index rindex={0}; + struct s_repeat_index windex={0}; + int nri=0,mri=0,ri=0; + int nwi=0,mwi=0,wi=0; + /* state machine trigger */ + int waiting_quote=0,lquote=0; + int macro_trigger=0; + int escape_code=0; + int quote_type=0; + int incbin=0,include=0,crunch=0; + int rewrite=0,hadcomma=0; + int nbinstruction; + int ifast,texpr; + int ispace=0; + char opassign=0; + /* incbin bug */ + int incstartL=0; + char *original_filename=NULL; + + + +#if TRACE_GENERALE +printf("*** preprocessing ***\n"); +#endif + +#if TRACE_PREPRO +printf("start prepro, alloc assenv\n"); +#endif + + windex.cl=-1; + windex.cidx=-1; + rindex.cl=-1; + rindex.cidx=-1; + +#if TRACE_PREPRO +printf("malloc+memset\n"); +#endif + ae=MemMalloc(sizeof(struct s_assenv)); + memset(ae,0,sizeof(struct s_assenv)); + + ae->module_separator[0]='_'; +#if TRACE_PREPRO +printf("paramz 1\n"); +#endif + if (param) { + ae->export_local=param->export_local; + ae->export_sym=param->export_sym; + ae->export_var=param->export_var; + ae->export_equ=param->export_equ; + ae->export_sna=param->export_sna; + ae->export_snabrk=param->export_snabrk; + if (param->export_sna || param->export_snabrk) { + ae->forcesnapshot=1; + } + ae->export_brk=param->export_brk; + ae->warn_unused=param->warn_unused; + ae->display_stats=param->display_stats; + ae->edskoverwrite=param->edskoverwrite; + ae->rough=param->rough; + ae->as80=param->as80; + ae->pasmo=param->pasmo; + ae->dams=param->dams; + ae->macrovoid=param->macrovoid; + if (param->v2) { + ae->forcesnapshot=1; + ae->snapshot.version=2; + } else { + ae->snapshot.version=3; + } + ae->xpr=param->xpr; + ae->cprinfo=param->cprinfo; + ae->cprinfo_export=param->cprinfoexport; + ae->cprinfo_filename=param->cprinfo_name; + ae->maxerr=param->maxerr; + ae->extended_error=param->extended_error; + ae->nowarning=param->nowarning; + ae->erronwarn=param->erronwarn; + ae->utf8enable=param->utf8enable; + ae->freequote=param->freequote; + ae->breakpoint_name=param->breakpoint_name; + ae->symbol_name=param->symbol_name; + ae->binary_name=param->binary_name; + ae->flexible_export=param->flexible_export; + ae->cartridge_name=param->cartridge_name; + ae->snapshot_name=param->snapshot_name; + ae->tape_name=param->tape_name; + ae->rom_name=param->rom_name; + ae->checkmode=param->checkmode; + ae->noampersand=param->noampersand; + ae->module_separator[0]=param->module_separator; + ae->enforce_symbol_case=param->enforce_symbol_case; + if (param->rough) ae->maxam=0; else ae->maxam=1; + /* additional symbols */ + for (i=0;insymb;i++) { + char *sep; + sep=strchr(param->symboldef[i],'='); + if (sep) { + *sep=0; + ExpressionSetDicoVar(ae,param->symboldef[i],atof(sep+1),0); // not external as default + } + } + if (param->msymb) { + MemFree(param->symboldef); + param->nsymb=param->msymb=0; + } + /* include paths */ + ae->includepath=param->pathdef; + ae->ipath=param->npath; + ae->mpath=param->mpath; + /* old inline params */ + ae->dependencies=param->dependencies; + } +#if TRACE_PREPRO +printf("init 0 amper=%d\n",ae->noampersand); +#endif +#if TRACE_GENERALE +printf("-init\n"); +#endif + /* generic init */ + ae->ctx1.maxivar=1; + ae->ctx2.maxivar=1; + ae->computectx=&ae->ctx1; + ae->flux=flux; + /* check snapshot structure */ + if (sizeof(ae->snapshot)!=0x100 || &ae->snapshot.fdd.motorstate-(unsigned char*)&ae->snapshot!=0x9C || &ae->snapshot.crtcstate.model-(unsigned char*)&ae->snapshot!=0xA4 + || &ae->snapshot.romselect-(unsigned char*)&ae->snapshot!=0x55 + || &ae->snapshot.interruptrequestflag-(unsigned char*)&ae->snapshot!=0xB4 + || &ae->snapshot.CPCType-(unsigned char*)&ae->snapshot!=0x6D) { + rasm_printf(ae,"snapshot structure integrity check KO\n"); + exit(349); + } + + for (i=0;i<4;i++) { + ae->bankgate[i]=0x7FC0; /* video memory has no paging */ + ae->setgate[i]=0x7FC0; /* video memory has no paging */ + } + for (i=0;i<256;i++) { + /* 4M expansion support on lower gate array port */ + ae->bankgate[i+4]=0x7FC4+(i&3)+((i&31)>>2)*8-0x100*(i>>5); + ae->setgate[i+4] =0x7FC2 +((i&31)>>2)*8-0x100*(i>>5); + //printf("%04X %04X\n",ae->bankgate[i+4],ae->setgate[i+4]); + } + + memcpy(ae->snapshot.idmark,"MV - SNA",8); + ae->snapshot.registers.IM=1; + + ae->snapshot.gatearray.palette[0]=0x04; + ae->snapshot.gatearray.palette[1]=0x0A; + ae->snapshot.gatearray.palette[2]=0x15; + ae->snapshot.gatearray.palette[3]=0x1C; + ae->snapshot.gatearray.palette[4]=0x18; + ae->snapshot.gatearray.palette[5]=0x1D; + ae->snapshot.gatearray.palette[6]=0x0C; + ae->snapshot.gatearray.palette[7]=0x05; + ae->snapshot.gatearray.palette[8]=0x0D; + ae->snapshot.gatearray.palette[9]=0x16; + ae->snapshot.gatearray.palette[10]=0x06; + ae->snapshot.gatearray.palette[11]=0x17; + ae->snapshot.gatearray.palette[12]=0x1E; + ae->snapshot.gatearray.palette[13]=0x00; + ae->snapshot.gatearray.palette[14]=0x1F; + ae->snapshot.gatearray.palette[15]=0x0E; + ae->snapshot.gatearray.palette[16]=0x04; + + ae->snapshot.gatearray.multiconfiguration=0x8D; // lower/upper ROM off + mode 1 + ae->snapshot.CPCType=2; /* 6128 */ + ae->snapshot.crtcstate.model=0; /* CRTC 0 */ + ae->snapshot.vsyncdelay=2; + strncpy((char *)ae->snapshot.unused6+3+0x20,RASM_VERSION,sizeof(ae->snapshot.unused6)-1-(3+0x20)); + /* CRTC default registers */ + ae->snapshot.crtc.registervalue[0]=0x3F; + ae->snapshot.crtc.registervalue[1]=40; + ae->snapshot.crtc.registervalue[2]=46; + ae->snapshot.crtc.registervalue[3]=0x8E; + ae->snapshot.crtc.registervalue[4]=38; + ae->snapshot.crtc.registervalue[6]=25; + ae->snapshot.crtc.registervalue[7]=30; + ae->snapshot.crtc.registervalue[9]=7; + ae->snapshot.crtc.registervalue[12]=0x30; + ae->snapshot.psg.registervalue[7]=0x3F; /* audio mix all channels OFF */ + /* PPI Init */ + ae->snapshot.ppi.control=0x82; + /* standard stack */ + ae->snapshot.registers.HSP=0xC0; + + ae->repeat_start=1; + ae->repeat_increment=1; + + /* + Winape sprintf(symbol_line,"%s #%4X\n",ae->label[i].name,ae->label[i].ptr); + pasmo sprintf(symbol_line,"%s EQU 0%4XH\n",ae->label[i].name,ae->label[i].ptr); + rasm sprintf(symbol_line,"%s #%X B%d\n",ae->wl[ae->label[i].iw].w,ae->label[i].ptr,ae->label[i].ibank>31?0:ae->label[i].ibank); + */ +#if TRACE_PREPRO +printf("paramz\n"); +#endif + if (param && param->labelfilename) { + for (j=0;param->labelfilename[j] && param->labelfilename[j][0];j++) { + rasm_printf(ae,"Label import from [%s]\n",param->labelfilename[j]); + ae->label_filename=param->labelfilename[j]; + ae->label_line=1; + labelines=FileReadLines(ae,param->labelfilename[j]); + + curlabel.fileidx=ae->ifile; + FieldArrayAddDynamicValueConcat(&ae->filename,&ae->ifile,&ae->maxfile,filename); // besoin de la casse + + if (ae->enforce_symbol_case) { + ae->rawfile=MemRealloc(ae->rawfile,sizeof(char **)*ae->ifile); + ae->rawlen=MemRealloc(ae->rawlen,sizeof(int)*ae->ifile); + ae->rawfile[ae->ifile-1]=ae->source_bigbuffer; + ae->rawlen[ae->ifile-1]=ae->source_bigbuffer_len; + } + + i=0; + while (labelines[i]) { + int k; + /* upper case */ + for (k=0;labelines[i][k];k++) labelines[i][k]=toupper(labelines[i][k]); + + if ((labelsep1=strstr(labelines[i],": EQU 0"))!=NULL) { + /* sjasm */ + *labelsep1=0; + curlabel.name=labelines[i]; + curlabel.iw=-1; + curlabel.crc=GetCRC(curlabel.name); + curlabel.ptr=strtol(labelsep1+6,NULL,16); + PushLabelLight(ae,&curlabel); + } else if ((labelsep1=strstr(labelines[i]," EQU 0"))!=NULL) { + /* pasmo */ + *labelsep1=0; + curlabel.name=labelines[i]; + curlabel.iw=-1; + curlabel.crc=GetCRC(curlabel.name); + curlabel.ptr=strtol(labelsep1+6,NULL,16); + //ObjectArrayAddDynamicValueConcat((void **)&ae->label,&ae->il,&ae->ml,&curlabel,sizeof(curlabel)); + PushLabelLight(ae,&curlabel); + } else if ((labelsep1=strstr(labelines[i]," "))!=NULL) { + /* Winape / rasm */ + if (*(labelsep1+1)=='#') { + *labelsep1=0; + curlabel.name=labelines[i]; + curlabel.iw=-1; + curlabel.crc=GetCRC(curlabel.name); + curlabel.ptr=strtol(labelsep1+2,NULL,16); + //ObjectArrayAddDynamicValueConcat((void **)&ae->label,&ae->il,&ae->ml,&curlabel,sizeof(curlabel)); + PushLabelLight(ae,&curlabel); + } + } + i++; + ae->label_line++; + } + MemFree(labelines); + } + ae->label_filename=NULL; + ae->label_line=0; + } +#if TRACE_PREPRO +printf("init 3\n"); +#endif + /* 32 CPR default roms but 260+ max snapshot RAM pages + one workspace */ + for (i=0;imem,&ae->nbbank,&ae->maxbank,&mem,sizeof(mem)); + } +#if TRACE_PREPRO +printf("nbbank=%d initialised\n",ae->nbbank); +#endif + ae->activebank=BANK_MAX_NUMBER; + ae->maxptr=65536; + for (i=0;i<256;i++) { ae->charset[i]=(unsigned char)i; } + + if (param && param->outputfilename) { + ae->outputfilename=TxtStrDup(param->outputfilename); + } else if (param && param->automatic_radix && param->filename) { + int rilook; + rilook=strlen(param->filename); + ae->outputfilename=TxtStrDup(param->filename); + /* look for extension */ + while (rilook && ae->outputfilename[rilook]!='.') { + /* end of scan with directory reference or nothing found */ + if (ae->outputfilename[rilook]=='/' || ae->outputfilename[rilook]=='\\') rilook=0; else rilook--; + } + if (ae->outputfilename[rilook]=='.') { + ae->outputfilename[rilook]=0; + } + } else { + ae->outputfilename=TxtStrDup("rasmoutput"); + } + /* si on est en ligne de commande ET que le fichier n'est pas trouvé */ + if (param && param->filename && !FileExists(param->filename)) { + char *LTryExtension[]={".asm",".z80",".inc",".src",".dam",".mxm",".txt", + ".ASM",".Z80",".INC",".SRC",".DAM",".MXM",".TXT",".o",".s",".O",".S","",NULL}; + + int iguess=1; +#if TRACE_PREPRO + printf("TRY EXT\n"); +#endif + original_filename=TxtStrDup(param->filename); + l=strlen(param->filename); + param->filename=MemRealloc(param->filename,l+6); + /* add fake filetype without dot if not present but a dot */ + if (param->filename[l-1]=='.') { + strcat(param->filename,"asm"); + } else { + /* if no filetype at all and no dot, add it */ + int eidx=l-1; + + while (eidx) { + if (param->filename[eidx]=='.') { + param->filename[eidx]=0; + break; + } else if (param->filename[eidx]=='/' || param->filename[eidx]=='\\') { + break; + } else { + eidx--; + } + } + strcat(param->filename,".asm"); + } + + while (!FileExists(param->filename) && LTryExtension[iguess]!=NULL) { + /* no realloc with this BECAUSE every replace is equal or smaller than the previous one */ + TxtReplace(param->filename,LTryExtension[iguess-1],LTryExtension[iguess],0); +#if TRACE_PREPRO + printf("TRY [%s]\n",param->filename); +#endif + if (!FileExists(param->filename)) { + param->filename[l]=0; + } + iguess++; + } + filename=param->filename; + } + + if (param && param->filename && !FileExists(param->filename)) { + char *filename_toread; + int fileok=0,ilookfile; +#if TRACE_PREPRO + printf("TRY %d include path(s)\n",ae->ipath); +#endif + /* search the very first file into include paths */ + for (ilookfile=0;ilookfileipath && !fileok;ilookfile++) { + filename_toread=MergePath(ae,ae->includepath[ilookfile],original_filename); +#if TRACE_PREPRO + printf("TRY [%s]\n",filename_toread); +#endif + if (FileExists(filename_toread)) { + fileok=1; + } + } + if (fileok) { + filename=TxtStrDup(filename_toread); // overwrite original filename + } else { + // we tried, we tried, but hey, nothing found! + rasm_printf(ae,"Cannot find file [%s]\n",param->filename); + exit(-1802); + } + } + if (original_filename) MemFree(original_filename); + + if (param) rasm_printf(ae,KAYGREEN"Pre-processing [%s]\n",param->filename); + for (nbinstruction=0;instruction[nbinstruction].mnemo[0];nbinstruction++); + qsort(instruction,nbinstruction,sizeof(struct s_asm_keyword),cmpkeyword); + for (i=0;i<256;i++) { ae->fastmatch[i]=-1; } + for (i=0;ifastmatch[(int)instruction[i].mnemo[0]]==-1) ae->fastmatch[(int)instruction[i].mnemo[0]]=i; } + for (i=0;CharWord[i];i++) {Automate[((int)CharWord[i])&0xFF]=1;} + for (i=0;i<256;i++) { + if (((i>='A' && i<='Z') || (i>='0' && i<='9') || i=='@' || i=='_') && !quote_type) AutomatePrepro[i]=1; else AutomatePrepro[i]=0; + } + /* separators */ + Automate[' ']=2; + Automate[',']=2; + Automate['\t']=2; + /* end of line */ + Automate[':']=3; /* les 0x0A et 0x0D seront deja  remplaces en ':' */ + /* expression */ + Automate['=']=4; /* on stocke l'emplacement de l'egalite */ + Automate['<']=4; /* ou des operateurs */ + Automate['>']=4; /* d'evaluation */ + Automate['!']=4; + + StateMachineResizeBuffer(&w,256,&mw); + StateMachineResizeBuffer(&bval,256,&sval); + StateMachineResizeBuffer(&qval,256,&sqval); + w[0]=0; + bval[0]=0; + qval[0]=0; + +#if TRACE_PREPRO +printf("read file/flux\n"); +#endif +#if TRACE_GENERALE +printf("-read/flux\n"); +#endif + + if (!ae->flux) { + zelines=FileReadLines(ae,filename); + FieldArrayAddDynamicValueConcat(&ae->filename,&ae->ifile,&ae->maxfile,filename); + if (ae->enforce_symbol_case) { + ae->rawfile=MemRealloc(ae->rawfile,sizeof(char **)*ae->ifile); + ae->rawlen=MemRealloc(ae->rawlen,sizeof(int)*ae->ifile); + ae->rawfile[ae->ifile-1]=ae->source_bigbuffer; + ae->rawlen[ae->ifile-1]=ae->source_bigbuffer_len; + } + } else { + int flux_nblines=0; + int flux_curpos; + + /* copie des données */ + for (i=0;iflux_curpos) { + zelines[flux_nblines]=MemMalloc(i-flux_curpos+1); + memcpy(zelines[flux_nblines],datain+flux_curpos,i-flux_curpos); + zelines[flux_nblines][i-flux_curpos]=0; + flux_nblines++; + } + /* terminator */ + zelines[flux_nblines]=NULL; + + /* with embedded Rasm we set the current directory of the caller as reference */ + FieldArrayAddDynamicValueConcat(&ae->filename,&ae->ifile,&ae->maxfile,CURRENT_DIR); + } + +#if TRACE_PREPRO +printf("remove comz, do includes\n"); +#endif +#if TRACE_GENERALE +printf("-comz/include\n"); +#endif + EarlyPrepSrc(ae,zelines,ae->filename[ae->ifile-1]); + + for (i=0;zelines[i];i++) { + curlisting.ifile=0; + curlisting.iline=i+1; + curlisting.listing=zelines[i]; + ObjectArrayAddDynamicValueConcat((void**)&listing,&ilisting,&maxlisting,&curlisting,sizeof(curlisting)); + } + MemFree(zelines); + + /* on s'assure que la derniere instruction est prise en compte a peu de frais */ + if (ilisting) { + datalen=strlen(listing[ilisting-1].listing); + listing[ilisting-1].listing=MemRealloc(listing[ilisting-1].listing,datalen+2); + listing[ilisting-1].listing[datalen]=':'; + listing[ilisting-1].listing[datalen+1]=0; + } + + waiting_quote=quote_type=0; + + /************************************************************************************/ + /************************************************************************************/ + /* simplify case, carriage return and some tricky quotes ****************************/ + /* also do all sources and binaries includes ****************************************/ + /************************************************************************************/ + /************************************************************************************/ + l=idx=0; + while (l2 && strncmp(&listing[l].listing[idx-3],"AF'",3)==0) { + /* nothing */ + } else { + if (!quote_type) { + quote_type=c; + lquote=l; + } else { + if (c==quote_type) { + quote_type=0; + } + } + } + } else if (c=='"') { + if (!quote_type) { + quote_type=c; + lquote=l; + } else { + if (c==quote_type) { + quote_type=0; + } + } + } + + if (waiting_quote) { + /* expecting quote and NOTHING else */ + switch (waiting_quote) { + case 1: + if (c==quote_type) waiting_quote=2; else { + /* enforce there is only spaces or tabs between READ/INC and string */ + if (c!=' ' && c!=0x9) { + MakeError(ae,ae->filename[listing[l].ifile],listing[l].iline,"A quoted string must follow INCLUDE/READ directive\n"); + waiting_quote=0; + idx--; + continue; + } + } + break; + case 2: + if (!quote_type) { + waiting_quote=3; + qval[iqval]=0; + } else { + qval[iqval++]=c; + StateMachineResizeBuffer(&qval,iqval,&sqval); + qval[iqval]=0; + } + } + if (waiting_quote==3) { + if (incbin) { + int fileok=0,ilookfile; + /* qval contient le nom du fichier a lire */ + filename_toread=MergePath(ae,ae->filename[listing[l].ifile],qval); + if (FileExists(filename_toread)) { + fileok=1; + } else { + for (ilookfile=0;ilookfileipath && !fileok;ilookfile++) { + filename_toread=MergePath(ae,ae->includepath[ilookfile],qval); + if (FileExists(filename_toread)) { + fileok=1; + } + } + } + curhexbin.filename=TxtStrDup(filename_toread); + curhexbin.crunch=crunch; + switch (crunch) { + case 18: + curhexbin.version=1; + curhexbin.minmatch=5; + break; + case 19: + curhexbin.crunch=18; + curhexbin.version=2; + curhexbin.minmatch=2; + break; + default:break; + } + + /* TAG + info */ + curhexbin.datalen=-1; + curhexbin.data=NULL; + /* not yet an error, we will know later when executing the code */ + ObjectArrayAddDynamicValueConcat((void**)&ae->hexbin,&ae->ih,&ae->mh,&curhexbin,sizeof(curhexbin)); + + /* v0.130 handling error case with filename on multiple lines */ + if (incstartL!=l) { + int iconcat=incstartL; + int ilen; + + MakeError(ae,ae->filename[listing[incstartL].ifile],listing[incstartL].iline,"INCBIN filename cannot be on multiple lines\n"); + + ilen=strlen(listing[iconcat].listing)+1; + idx+=ilen-rewrite; + while (iconcatih--; + } else { + /* insertion */ + le=strlen(listing[l].listing); + + newlistingline=MemMalloc(le+32); + memcpy(newlistingline,listing[l].listing,rewrite); + rewrite+=sprintf(newlistingline+rewrite,"HEXBIN #%X",ae->ih-1); + strcat(newlistingline+rewrite,listing[l].listing+idx); + idx=rewrite; + MemFree(listing[l].listing); + listing[l].listing=newlistingline; + } + incbin=0; + } else if (include) { + /* qval contient le nom du fichier a lire */ + int fileok=0,ilookfile; + /* cette notion n'existe pas dans le cas normal */ + curhexbin.datalen=0; + /* qval contient le nom du fichier a lire */ + filename_toread=MergePath(ae,ae->filename[listing[l].ifile],qval); + if (FileExists(filename_toread)) { + fileok=1; + } else { + for (ilookfile=0;ilookfileipath && !fileok;ilookfile++) { + filename_toread=MergePath(ae,ae->includepath[ilookfile],qval); + if (FileExists(filename_toread)) { + fileok=1; + } + } + } + + /* v0.130 handling error case with filename on multiple lines */ + if (incstartL!=l) { + int iconcat=incstartL; + int ilen; + + MakeError(ae,ae->filename[listing[incstartL].ifile],listing[incstartL].iline,"INCLUDE filename cannot be on multiple lines\n"); + ilen=strlen(listing[iconcat].listing)+1; + idx+=ilen-rewrite; + while (iconcatfilename,&ae->ifile,&ae->maxfile,filename_toread); + if (ae->enforce_symbol_case) { + ae->rawfile=MemRealloc(ae->rawfile,sizeof(char **)*ae->ifile); + ae->rawlen=MemRealloc(ae->rawlen,sizeof(int)*ae->ifile); + ae->rawfile[ae->ifile-1]=ae->source_bigbuffer; + ae->rawlen[ae->ifile-1]=ae->source_bigbuffer_len; + } + /* virer les commentaires + pré-traitement */ + EarlyPrepSrc(ae,listing_include,ae->filename[ae->ifile-1]); + + /* split de la ligne en cours + suppression de l'instruction include */ + PreProcessingSplitListing(&listing,&ilisting,&maxlisting,l,rewrite,idx); + /* insertion des nouvelles lignes + reference fichier + numeros de ligne */ + PreProcessingInsertListing(&listing,&ilisting,&maxlisting,l,listing_include,ae->ifile-1); + + MemFree(listing_include); /* free le tableau mais pas les lignes */ + listing_include=NULL; + idx=0; /* on reste sur la meme ligne mais on se prepare a relire du caractere 0! */ + } else { + /******************************************** + * E R R O R M a n a g e m e n t * + ********************************************/ + char tmp_insert[128]; + + for (i=rewrite;iih); + memcpy(listing[incstartL].listing+rewrite,tmp_insert,strlen(tmp_insert)); + + filename_toread=MergePath(ae,ae->filename[listing[l].ifile],qval); + curhexbin.filename=TxtStrDup(filename_toread); + curhexbin.crunch=crunch; + + /* TAG + info */ + curhexbin.datalen=-2; + curhexbin.data=NULL; + /* not yet an error, we will know later when executing the code */ + ObjectArrayAddDynamicValueConcat((void**)&ae->hexbin,&ae->ih,&ae->mh,&curhexbin,sizeof(curhexbin)); + } + } + include=0; + } + waiting_quote=0; + qval[0]=0; + iqval=0; + } + } else { + /* classic behaviour */ + + /* looking for include/incbin */ + //if (((c>='A' && c<='Z') || (c>='0' && c<='9') || c=='@' || c=='_')&& !quote_type) { + if (AutomatePrepro[((int)c)&0xFF] && !quote_type) { + bval[ival++]=c; + StateMachineResizeBuffer(&bval,ival,&sval); + bval[ival]=0; + } else { + switch (bval[0]) { + case 'I': + if (bval[1]=='N' && bval[2]=='C') { + if (strcmp(bval,"INCLUDE")==0) { + incstartL=l; + include=1; + waiting_quote=1; + rewrite=idx-7-1; + /* quote right after keyword */ + if (c==quote_type) { + waiting_quote=2; + } + } else if (strcmp(bval,"INCLZSA2")==0) { + incstartL=l; + incbin=1; + crunch=19; + waiting_quote=1; + rewrite=idx-8-1; + /* quote right after keyword */ + if (c==quote_type) { + waiting_quote=2; + } + } else if (strcmp(bval,"INCLZSA1")==0) { + incstartL=l; + incbin=1; + crunch=18; + waiting_quote=1; + rewrite=idx-8-1; + /* quote right after keyword */ + if (c==quote_type) { + waiting_quote=2; + } + } else if (strcmp(bval,"INCAPU")==0) { + incstartL=l; + incbin=1; + crunch=17; + waiting_quote=1; + rewrite=idx-6-1; + /* quote right after keyword */ + if (c==quote_type) { + waiting_quote=2; + } + } else if (strcmp(bval,"INCLZ4")==0) { + incstartL=l; + incbin=1; + crunch=4; + waiting_quote=1; + rewrite=idx-6-1; + /* quote right after keyword */ + if (c==quote_type) { + waiting_quote=2; + } + } else if (strcmp(bval,"INCEXO")==0) { + incstartL=l; + incbin=1; + crunch=8; + waiting_quote=1; + rewrite=idx-6-1; + /* quote right after keyword */ + if (c==quote_type) { + waiting_quote=2; + } + } else if (strcmp(bval,"INCZX0")==0) { + incstartL=l; + incbin=1; + crunch=70; + waiting_quote=1; + rewrite=idx-6-1; + /* quote right after keyword */ + if (c==quote_type) { + waiting_quote=2; + } + } else if (strcmp(bval,"INCZX0B")==0) { + incstartL=l; + incbin=1; + crunch=71; + waiting_quote=1; + rewrite=idx-7-1; + /* quote right after keyword */ + if (c==quote_type) { + waiting_quote=2; + } + } else if (strcmp(bval,"INCZX7")==0) { + incstartL=l; + incbin=1; + crunch=7; + waiting_quote=1; + rewrite=idx-6-1; + /* quote right after keyword */ + if (c==quote_type) { + waiting_quote=2; + } + } else if (strcmp(bval,"INCL48")==0) { + incstartL=l; + incbin=1; + crunch=48; + waiting_quote=1; + rewrite=idx-6-1; + /* quote right after keyword */ + if (c==quote_type) { + waiting_quote=2; + } + } else if (strcmp(bval,"INCL49")==0) { + incstartL=l; + incbin=1; + crunch=49; + waiting_quote=1; + rewrite=idx-6-1; + /* quote right after keyword */ + if (c==quote_type) { + waiting_quote=2; + } + } else if (strcmp(bval,"INCBIN")==0) { + incstartL=l; + incbin=1; + crunch=0; + waiting_quote=1; + rewrite=idx-6-1; + /* quote right after keyword */ + if (c==quote_type) { + waiting_quote=2; + } + } else if (strcmp(bval,"INCWAV")==0) { + incstartL=l; + incbin=1; + crunch=0; + waiting_quote=1; + rewrite=idx-6-1; + /* quote right after keyword */ + if (c==quote_type) { + waiting_quote=2; + } + } + } + break; + + case 'U': + /* code dupliqué du REND */ + if (strcmp(bval,"UNTIL")==0) { + /* retrouver la structure repeat_index correspondant a l'ouverture */ + for (ri=nri-1;ri>=0;ri--) { + if (TABrindex[ri].cl==-1) { + TABrindex[ri].cl=c; + TABrindex[ri].cidx=idx; + break; + } + } + if (ri==-1) { + MakeError(ae,ae->filename[listing[l].ifile],listing[l].iline,"%s refers to unknown REPEAT\n",bval); + //exit(1); + } + } + break; + + case 'R': + if (strcmp(bval,"READ")==0) { + incstartL=l; + include=1; + waiting_quote=1; + rewrite=idx-4-1; + /* quote right after keyword */ + if (c==quote_type) { + waiting_quote=2; + } + /* code dupliqué du UNTIL */ + } else if (strcmp(bval,"REND")==0) { + /* retrouver la structure repeat_index correspondant a l'ouverture */ + for (ri=nri-1;ri>=0;ri--) { + if (TABrindex[ri].cl==-1) { + TABrindex[ri].cl=c; + TABrindex[ri].cidx=idx; + break; + } + } + if (ri==-1) { + MakeError(ae,ae->filename[listing[l].ifile],listing[l].iline,"%s refers to unknown REPEAT\n",bval); + //exit(1); + } + } else if (strcmp(bval,"REPEAT")==0) { + /* remplir la structure repeat_index */ + rindex.ol=listing[l].iline; + rindex.oidx=idx; + rindex.ifile=ae->ifile-1; + ObjectArrayAddDynamicValueConcat((void**)&TABrindex,&nri,&mri,&rindex,sizeof(rindex)); + } + break; + + case 'W': + if (strcmp(bval,"WHILE")==0) { + /* remplir la structure repeat_index */ + windex.ol=listing[l].iline; + windex.oidx=idx; + windex.ifile=ae->ifile-1; + ObjectArrayAddDynamicValueConcat((void**)&TABwindex,&nwi,&mwi,&windex,sizeof(windex)); + } else if (strcmp(bval,"WEND")==0) { + /* retrouver la structure repeat_index correspondant a l'ouverture */ + for (wi=nwi-1;wi>=0;wi--) { + if (TABwindex[wi].cl==-1) { + TABwindex[wi].cl=c; + TABwindex[wi].cidx=idx; + break; + } + } + if (wi==-1) { + MakeError(ae,ae->filename[listing[l].ifile],listing[l].iline,"WEND refers to unknown WHILE\n"); + //exit(1); + } + + } + break; + + default: if (ae->noampersand && c=='&') { + listing[l].listing[idx-1]='#'; +#if TRACE_PREPRO +printf("patch & => #\n"); +#endif + } + break; + } + +#if TRACE_PREPRO +printf("bval=[%s]\n",bval); +#endif + bval[0]=0; + ival=0; + } + } + } + if (waiting_quote && ilisting) { + MakeError(ae,ae->filename[listing[ilisting-1].ifile],listing[ilisting-1].iline,"A quoted string must follow INCLUDE/READ directive\n"); + } + +#if TRACE_PREPRO +printf("check quotes and repeats\n"); +#endif + if (quote_type) { + MakeError(ae,ae->filename[listing[lquote].ifile],listing[lquote].iline,"quote opened was not closed\n"); + //exit(1); + } + + /* repeat expansion check */ + for (ri=0;rifilename[TABrindex[ri].ifile],TABrindex[ri].ol,"REPEAT was not closed\n"); + } + } + + /* creer une liste de mots */ + curw.w=TxtStrDup("BEGIN"); + curw.l=0; + curw.ifile=0; + curw.t=1; + curw.e=0; + ObjectArrayAddDynamicValueConcat((void**)&wordlist,&nbword,&maxword,&curw,sizeof(curw)); + + /* pour les calculs d'adresses avec IX et IY on enregistre deux variables bidons du meme nom */ + curw.e=2; + curw.w=TxtStrDup("IX~0"); + ObjectArrayAddDynamicValueConcat((void**)&wordlist,&nbword,&maxword,&curw,sizeof(curw)); + curw.w=TxtStrDup("IY~0"); + ObjectArrayAddDynamicValueConcat((void**)&wordlist,&nbword,&maxword,&curw,sizeof(curw)); + curw.e=0; + +#if TRACE_PREPRO + l=0; + while (l31?c:'.',Automate[((int)c)&0xFF]); +#endif + switch (Automate[((int)c)&0xFF]) { + case 0: + MakeError(ae,ae->filename[listing[l].ifile],listing[l].iline,"invalid char '%c' (%d) char %d\n",c,c,idx); +#if TRACE_PREPRO +printf("c='%c' automate[c]=%d\n",c>31?c:'.',Automate[((int)c)&0xFF]); +#endif + exit(1); + break; + case 1: + if (c=='\'') { + if (idx>2 && strncmp(&listing[l].listing[idx-3],"AF'",3)==0) { + w[lw++]=c; + StateMachineResizeBuffer(&w,lw,&mw); + w[lw]=0; + break; + } +#if TRACE_PREPRO +printf("quote\n"); +#endif + /* on finalise le mot si on est en début d'une nouvelle instruction ET que c'est un SAVE */ + if (strcmp(w,"SAVE")==0) { + // on ne break pas pour passer dans le case 2 (separator) + idx--; + } else { + quote_type=c; + w[lw++]=c; + StateMachineResizeBuffer(&w,lw,&mw); + w[lw]=0; + break; + } + } else if (c=='"') { +#if TRACE_PREPRO +printf("quote\n"); +#endif + /* on finalise le mot si on est en début d'une nouvelle instruction ET que c'est un SAVE */ + if (strcmp(w,"SAVE")==0) { + // on ne break pas pour passer dans le case 2 (separator) + idx--; + } else { + quote_type=c; + w[lw++]=c; + StateMachineResizeBuffer(&w,lw,&mw); + w[lw]=0; + break; + } + } else { + if (c!=' ' && c!='\t') { + w[lw++]=c; + StateMachineResizeBuffer(&w,lw,&mw); + w[lw]=0; + } else { + /* Winape/Maxam operator compatibility on expressions */ +#if TRACE_PREPRO +printf("1/2 Winape maxam operator test for [%s]\n",w+ispace); +#endif + if (texpr) { + if (strcmp(w+ispace,"AND")==0) { + w[ispace]='&'; + lw=ispace+1; + } else if (strcmp(w+ispace,"OR")==0) { +#if TRACE_PREPRO +printf("conversion OR vers |\n"); +#endif + w[ispace]='|'; + lw=ispace+1; + } else if (strcmp(w+ispace,"MOD")==0) { + w[ispace]='m'; + lw=ispace+1; + } else if (strcmp(w+ispace,"XOR")==0) { + w[ispace]='^'; + lw=ispace+1; + } else if (strcmp(w+ispace,"%")==0) { + w[ispace]='m'; + lw=ispace+1; + } + } + ispace=lw; + } + break; + } + case 2: + /* separator (space, tab, comma) */ +#if TRACE_PREPRO +printf("*** separator='%c'\n",c); +#endif + + /* patch argument suit une expression d'évaluation (ASSERT) */ + if (c==',') hadcomma=1; + + if (lw) { + w[lw]=0; + if (texpr && !wordlist[nbword-1].t && wordlist[nbword-1].e && !hadcomma) { + /* pour compatibilite Winape avec AND,OR,XOR */ +#if TRACE_PREPRO +printf("2/2 Winape maxam operator test for expression [%s]\n",w+ispace); +#endif + if (strcmp(w,"AND")==0) { + wtmp=TxtStrDup("&"); + } else if (strcmp(w,"OR")==0) { + wtmp=TxtStrDup("|"); + } else if (strcmp(w,"XOR")==0) { + wtmp=TxtStrDup("^"); + } else if (strcmp(w,"%")==0) { + wtmp=TxtStrDup("m"); + } else { + wtmp=TxtStrDup(w); + } + /* on concatène le nouveau mot à l'expression */ + nbword--; + lw=0; + for (li=0;wordlist[nbword].w[li];li++) { + w[lw++]=wordlist[nbword].w[li]; + StateMachineResizeBuffer(&w,lw,&mw); + } + w[lw]=0; + MemFree(wordlist[nbword].w); + + for (li=0;wtmp[li];li++) { + w[lw++]=wtmp[li]; + StateMachineResizeBuffer(&w,lw,&mw); + } + w[lw]=0; + MemFree(wtmp); + /* et on modifie l'automate pour la suite! */ + Automate[' ']=1; + Automate['\t']=1; + ispace=lw; + } else if (strcmp(w,"EQU")==0) { + /* il y avait un mot avant alors on va reorganiser la ligne */ + nbword--; + lw=0; + for (li=0;wordlist[nbword].w[li];li++) { + w[lw++]=wordlist[nbword].w[li]; + StateMachineResizeBuffer(&w,lw,&mw); + } + MemFree(wordlist[nbword].w); + curw.e=lw+1; + /* on ajoute l'egalite d'alias*/ + w[lw++]='~'; + StateMachineResizeBuffer(&w,lw,&mw); + w[lw]=0; + Automate[' ']=1; + Automate['\t']=1; + ispace=lw; + texpr=1; + } else { + curw.w=TxtStrDup(w); + curw.l=listing[l].iline; + curw.ifile=listing[l].ifile; + curw.t=0; +#if TRACE_PREPRO +if (curw.w[0]=='=') { + printf("(1) bug prout\n"); + exit(1); +} +printf("ajout du mot [%s]\n",curw.w); +#endif + ObjectArrayAddDynamicValueConcat((void**)&wordlist,&nbword,&maxword,&curw,sizeof(curw)); + //texpr=0; /* reset expr */ + curw.e=0; + lw=0; + w[lw]=0; + + /* match keyword? then next spaces will be ignored*/ + if (macro_trigger) { + struct s_macro_fast curmacrofast; + Automate[' ']=1; + Automate['\t']=1; + ispace=0; + texpr=1; +#if TRACE_PREPRO +printf("macro trigger w=[%s]\n",curw.w); +#endif + /* add macro name to instruction pool for preprocessor but not struct or write */ + if (macro_trigger=='M') { + curmacrofast.mnemo=curw.w; + curmacrofast.crc=GetCRC(curw.w); + ObjectArrayAddDynamicValueConcat((void**)&MacroFast,&idxmacrofast,&maxmacrofast,&curmacrofast,sizeof(struct s_macro_fast)); + } + macro_trigger=0; + } else { + int keymatched=0; + if ((ifast=ae->fastmatch[(int)curw.w[0]])!=-1) { + while (instruction[ifast].mnemo[0]==curw.w[0]) { + if (strcmp(instruction[ifast].mnemo,curw.w)==0) { + keymatched=1; + if (strcmp(curw.w,"MACRO")==0 || strcmp(curw.w,"STRUCT")==0 || strcmp(curw.w,"WRITE")==0) { +/* @@TODO AS80 compatibility patch!!! */ + macro_trigger=curw.w[0]; + } else { + Automate[' ']=1; + Automate['\t']=1; + ispace=0; + /* instruction en cours, le reste est a interpreter comme une expression */ +#if TRACE_PREPRO +printf("instruction en cours\n"); +#endif + texpr=1; + } + break; + } + ifast++; + } + } + if (!keymatched) { + int macrocrc; + macrocrc=GetCRC(curw.w); + for (keymatched=0;keymatchedfilename[listing[l].ifile],listing[l].iline,"empty parameter\n"); + } + } + break; + case 3: + /* fin de ligne, on remet l'automate comme il faut */ +#if TRACE_PREPRO +printf("EOL\n"); +#endif + macro_trigger=0; + Automate[' ']=2; + Automate['\t']=2; + ispace=0; + texpr=0; + /* si le mot lu a plus d'un caractère */ + if (lw) { + if (!wordlist[nbword-1].t && (wordlist[nbword-1].e || w[0]=='=') && !hadcomma) { + /* cas particulier d'ecriture libre */ + /* bugfix inhibition 19.06.2018 */ + /* ajout du terminateur? */ + w[lw]=0; +#if TRACE_PREPRO +printf("nbword=%d w=[%s] ->",nbword,w);fflush(stdout); +#endif + nbword--; + wordlist[nbword].w=MemRealloc(wordlist[nbword].w,strlen(wordlist[nbword].w)+lw+1); + strcat(wordlist[nbword].w,w); +#if TRACE_PREPRO +printf("%s\n",wordlist[nbword].w); +#endif + /* on change de type! */ + wordlist[nbword].t=1; + //ObjectArrayAddDynamicValueConcat((void**)&wordlist,&nbword,&maxword,&curw,sizeof(curw)); + curw.e=0; + lw=0; + w[lw]=0; + } else if (nbword && strcmp(w,"EQU")==0) { + /* il y avait un mot avant alors on va reorganiser la ligne */ + nbword--; + lw=0; + for (li=0;wordlist[nbword].w[li];li++) { + w[lw++]=wordlist[nbword].w[li]; + StateMachineResizeBuffer(&w,lw,&mw); + w[lw]=0; + } + MemFree(wordlist[nbword].w); + /* on ajoute l'egalite ou comparaison! */ + curw.e=lw+1; + w[lw++]='='; + StateMachineResizeBuffer(&w,lw,&mw); + w[lw]=0; + Automate[' ']=1; + Automate['\t']=1; + } else { + /* mot de fin de ligne, à priori pas une expression */ + curw.w=TxtStrDup(w); + curw.l=listing[l].iline; + curw.ifile=listing[l].ifile; + curw.t=1; +#if TRACE_PREPRO +printf("mot de fin de ligne = [%s]\n",curw.w); +if (curw.w[0]=='=') { + printf("(3) bug prout\n"); + exit(1); +} +#endif + ObjectArrayAddDynamicValueConcat((void**)&wordlist,&nbword,&maxword,&curw,sizeof(curw)); + curw.e=0; + lw=0; + w[lw]=0; + hadcomma=0; + } + } else { + /* sinon c'est le précédent qui était terminateur d'instruction */ + wordlist[nbword-1].t=1; + w[lw]=0; + } + hadcomma=0; + break; + case 4: +#if TRACE_PREPRO +printf("expr operator=%c\n",c); +#endif + /* expression/condition */ + texpr=1; + + /* patch operator assignment with useless spacing v121 */ + if (lw==1 && c=='=') { + switch (w[0]) { + case '[':case ']':case '+':case '*':case '-':case '/':case '|':case '&': +#if TRACE_PREPRO +printf("*** patch prepro operator assignment + useless spacing\n"); +#endif + opassign=w[0];lw=0; + break; + default:opassign=0;break; + } + } else { + opassign=0; + } + + if (lw) { + Automate[' ']=1; + Automate['\t']=1; + if (!curw.e) { + curw.e=lw+1; + w[lw++]=c; + StateMachineResizeBuffer(&w,lw,&mw); + w[lw]=0; + } else { + w[lw++]=c; + StateMachineResizeBuffer(&w,lw,&mw); + w[lw]=0; + } + } else { + /* 2018.06.06 évolution sur le ! (not) */ +#if TRACE_PREPRO +printf("*** operateur commence le mot\n"); +printf("mot precedent=[%s] t=%d\n",wordlist[nbword-1].w,wordlist[nbword-1].t); +#endif + if (hadcomma && c=='!') { + /* on peut commencer un argument par un NOT */ + w[lw++]=c; + StateMachineResizeBuffer(&w,lw,&mw); + w[lw]=0; + /* automate déjà modifié rien de plus */ + } else if (!wordlist[nbword-1].t) { + /* il y avait un mot avant alors on va reorganiser la ligne */ + /* patch NOT -> SAUF si c'est une directive */ + int keymatched=0; + if ((ifast=ae->fastmatch[(int)wordlist[nbword-1].w[0]])!=-1) { + while (instruction[ifast].mnemo[0]==wordlist[nbword-1].w[0]) { + if (strcmp(instruction[ifast].mnemo,wordlist[nbword-1].w)==0) { + keymatched=1; + break; + } + ifast++; + } + } + if (!keymatched) { + int macrocrc; + macrocrc=GetCRC(wordlist[nbword-1].w); + for (i=0;ifilename[listing[l].ifile],listing[l].iline,"cannot start expression with '=','!','<','>'\n"); + } + } + break; + default: + rasm_printf(ae,KERROR"Internal error (Automate wrong value=%d)\n",Automate[c]); + exit(-1); + } + } else { +#if TRACE_PREPRO +printf("quote start with %c\n",c); +#endif + /* quoted string always starts with a single or a double quote */ + w[lw++]=c; + StateMachineResizeBuffer(&w,lw,&mw); + if (c=='\\') { + escape_code=1; + } else if (c==quote_type) { + quote_type=0; + } + + if (quote_type) // should not happend but... + do { + c=listing[l].listing[idx++]; + if (!c) { + MakeError(ae,ae->filename[listing[l].ifile],listing[l].iline,"Quoted string must be on a single line!\n"); + idx=0; + l++; + lw=0; // to avoid side effects + quote_type=0; // leave anyway + } else { + w[lw++]=c; + StateMachineResizeBuffer(&w,lw,&mw); + + // string is stored with quotes + if (!escape_code) { + if (c=='\\') { + escape_code=1; + } else if (c==quote_type) { + quote_type=0; + } + } else { + // if previous char is an escape char, do not take care about ending quote + escape_code=0; + } + } + } while (quote_type); + // EOL for new word! + w[lw]=0; + + if (ae->utf8enable) { + int utidx; + for (utidx=0;w[utidx];utidx++) { + if ((unsigned char)w[utidx]>126) { + switch ((unsigned char)w[utidx]) { + case 0xC2: + if ((unsigned char)w[utidx+1]==0xBF) w[utidx]=174; else // ¿ + if ((unsigned char)w[utidx+1]==0xA1) w[utidx]=175; else // ¡ + MakeError(ae,ae->filename[listing[l].ifile],listing[l].iline,"Unsupported UTF8 char for quoted string\n"); + break; + case 0xC3: + if ((unsigned char)w[utidx+1]==0xB9) w[utidx]=124; else // ù + if ((unsigned char)w[utidx+1]==0xA9) w[utidx]=123; else // é + if ((unsigned char)w[utidx+1]==0xA8) w[utidx]=125; else // è + if ((unsigned char)w[utidx+1]==0xA0) w[utidx]=64; else // à + if ((unsigned char)w[utidx+1]==0x91) w[utidx]=161; else // Ñ + if ((unsigned char)w[utidx+1]==0xB1) w[utidx]=171; else // ñ + if ((unsigned char)w[utidx+1]==0xA7) { // ç + w[utidx]=92; + w[utidx+1]=92; + } else + MakeError(ae,ae->filename[listing[l].ifile],listing[l].iline,"Unsupported UTF8 char for quoted string\n"); + break; + default: + MakeError(ae,ae->filename[listing[l].ifile],listing[l].iline,"Unsupported UTF8 char for quoted string\n"); + } + // shift string bytes except for \ char + if (w[utidx+1] && w[utidx+1]!=92) { + int utshift; + utshift=utidx+1; do { w[utshift]=w[utshift+1]; utshift++; } while (w[utshift]); + } + } + } + } else if (!ae->freequote) { + // control special chars except in freequote mode + int utidx; + for (utidx=0;w[utidx];utidx++) { + if ((w[utidx]>=32 && w[utidx]<127) || w[utidx]=='\t') { + // is ok + } else { + MakeError(ae,ae->filename[listing[l].ifile],listing[l].iline,"Invalid char for quoted string\n"); + } + } + } + +#if TRACE_PREPRO +printf("quote end w=%s\n",w); +#endif + } + } + +#if TRACE_PREPRO +printf("END\n"); +#endif + + // fix error in previous instruction + if (nbword && !wordlist[nbword-1].t) { + wordlist[nbword-1].t=1; + } + curw.w="END"; + curw.l=0; + curw.t=2; + curw.ifile=0; + ObjectArrayAddDynamicValueConcat((void**)&wordlist,&nbword,&maxword,&curw,sizeof(curw)); +#if TRACE_PREPRO + rasm_printf(ae,KVERBOSE"wordlist contains %d element%s\n",nbword,nbword>1?"s":""); +#endif + ae->nbword=nbword; + + /* switch words for macro declaration with AS80 & UZ80 */ + if (param && param->as80) { + for (l=0;lwl=wordlist; + if (param) { + MemFree(param->filename); + } + if (MacroFast) MemFree(MacroFast); + if (TABwindex) MemFree(TABwindex); + if (TABrindex) MemFree(TABrindex); +#if TRACE_PREPRO +printf("return ae\n"); +#endif + return ae; +} + +int Rasm(struct s_parameter *param) +{ + #undef FUNC + #define FUNC "Rasm" + + struct s_assenv *ae=NULL; + + /* read and preprocess source */ + ae=PreProcessing(param->filename,0,NULL,0,param); + /* assemble */ + return Assemble(ae,NULL,NULL,NULL); +} + +/* fonction d'export */ + +int RasmAssemble(const char *datain, int lenin, unsigned char **dataout, int *lenout) +{ + static int cpt=0; + struct s_assenv *ae=NULL; + + if (datain==NULL && lenin==0) return cpt; else cpt++; + + if (lenout) *lenout=0; + ae=PreProcessing(NULL,1,datain,lenin,NULL); + return Assemble(ae,dataout,lenout,NULL); +} + +int RasmAssembleInfo(const char *datain, int lenin, unsigned char **dataout, int *lenout, struct s_rasm_info **debug) +{ + static int cpt=0; + struct s_assenv *ae=NULL; + int ret; + + if (datain==NULL && lenin==0) return cpt; else cpt++; + + ae=PreProcessing(NULL,1,datain,lenin,NULL); + ret=Assemble(ae,dataout,lenout,debug); + return ret; +} + +int RasmAssembleInfoIntoRAM(const char *datain, int lenin, struct s_rasm_info **debug, unsigned char *emuram, int ramsize) +{ + static int cpt=0; + struct s_assenv *ae=NULL; + int ret; + int i,j,maxbank,ramidx; + + if (datain==NULL && lenin==0) return cpt; else cpt++; + + ae=PreProcessing(NULL,1,datain,lenin,NULL); + + /* extension 4Mo = 256 slots + 4 slots 64K de RAM par défaut => 260 */ + maxbank=ramsize>>14; + for (i=0;imem[i][j+16384*(i&3)]=emuram[ramidx++]; + } + } + /* remaining bytes, if any */ + ramidx=i*16384; + for (j=0;jmem[i][j+16384*(i&3)]=emuram[ramidx++]; + } + + ae->debug.emuram=emuram; + ae->debug.lenram=ramsize; + + ret=Assemble(ae,NULL,NULL,debug); + + return ret; +} + +int RasmAssembleInfoParam(const char *datain, int lenin, unsigned char **dataout, int *lenout, struct s_rasm_info **debug, struct s_parameter *param) +{ + static int cpt=0; + struct s_assenv *ae=NULL; + int ret; + + if (datain==NULL && lenin==0) return cpt; else cpt++; + + ae=PreProcessing(NULL,1,datain,lenin,param); + ret=Assemble(ae,dataout,lenout,debug); + return ret; +} + +#define AUTOTEST_ACCENT "defb 'grouiké'" + +#define AUTOTEST_QUOTELAST "nop : save'grouik" + +#define AUTOTEST_PAGELABELGEN "buildsna: bank: cpt=5: ld bc,{page}miam{cpt}: bank cpt: nop: miam{cpt} nop: assert {page}miam{cpt}==0x7FC5 " + +#define AUTOTEST_NOINCLUDE "truc equ 0:if truc:include'bite':endif:nop" + +#define AUTOTEST_BADINCLUDE "include 'truc\n .bin' \n nop nop" + +#define AUTOTEST_BADINCBIN "incl49 'truc\n .bin' \n nop nop" + +#define AUTOTEST_BADINCLUDE02 "read: ldir : cp ';'" + +#define AUTOTEST_SETINSIDE "ld hl,0=0xC9FB" + +#define AUTOTEST_OPERATOR_CONVERSION "ld hl,10 OR 20:ld a,40 and 10:ld bc,5 MOD 2:ld a,(ix+45 xor 45)" + +#define AUTOTEST_OPERATOR_MODULO "revar=46: devar=5 : var=46%5 : assert var==1: var=46 % 5 : assert var==1: var=46 mod 5 : assert var==1:" \ + "var=revar%5 : assert var==1: var=revar%devar : assert var==1: var=46%devar : assert var==1: var=revar % 5 : assert var==1:" \ + "var=revar % devar : assert var==1: var=46 % devar : assert var==1: var=revar % %101 : assert var==1: var=revar%%101 : assert var==1: nop" + +#define AUTOTEST_UNDEF "mavar=10: ifdef mavar: undef mavar: endif: ifdef mavar: fail 'undef did not work': endif:nop " + +#define AUTOTEST_INSTRMUSTFAILED "ld a,b,c:ldi a: ldir bc:exx hl,de:exx de:ex bc,hl:ex hl,bc:ex af,af:ex hl,hl:ex hl:exx hl: "\ + "neg b:push b:push:pop:pop c:sub ix:add ix:add:sub:di 2:ei 3:ld i,c:ld r,e:rl:rr:rlca a:sla:sll:"\ + "ldd e:lddr hl:adc ix:adc b,a:xor 12,13:xor b,1:xor:or 12,13:or b,1:or:and 12,13:and b,1:and:inc:dec" + +#define AUTOTEST_VIRGULE "defb 5,5,,5" +#define AUTOTEST_VIRGULE2 "print '5,,5':nop" + +#define AUTOTEST_OVERLOADMACPRM "macro test,idx: defb idx:endm:macro test2,idx:defb {idx}:endm:repeat 2,idx:test idx-1:test2 idx-1:rend" + +#define AUTOTEST_IFDEFMACRO "macro test:nop:endm:ifndef test:error:else:test:endif:ifdef test:test:else:error:endif:nop" + +#define AUTOTEST_PRINTVAR "label1: macro test, param: print 'param {param}', {hex}{param}: endm:: test label1: nop" + +#define AUTOTEST_PRINTSPACE "idx=5: print 'grouik { idx + 3 } ':nop" + +#define AUTOTEST_NOT "myvar=10:myvar=10+myvar:if 5!=3:else:print glop:endif:ifnot 5:print glop:else:endif:" \ + "ifnot 0:else:print glop:endif:if !(5):print glop:endif:if !(0):else:print glop:endif:" \ + "ya=!0:if ya==1:else:print glop:endif:if !5:print glop:endif:ya = 0:ya =! 0:if ya == 1:" \ + "else:print glop:endif:if ! 5:print glop:endif:if 1-!( !0 && !0):else:print glop:endif:nop" + + +#define AUTOTEST_MACRO "macro glop:@glop:ld hl,@next:djnz @glop:@next:mend:macro glop2:@glop:glop:ld hl,@next:djnz @glop:glop:" \ + "@next:mend:cpti=0:repeat:glop:cpt=0:glop:repeat:glop2:repeat 1:@glop:dec a:ld hl,@next:glop2:glop2:" \ + "jr nz,@glop:@next:rend:cpt=cpt+1:glop2:until cpt<3:cpti=cpti+1:glop2:until cpti<3" + +#define AUTOTEST_MACRO_ADV "idx=10:macro mac2 param1,param2:ld hl,{param1}{idx+10}{param2}:{param1}{idx+10}{param2}:djnz {param1}{idx+10}{param2}:mend: " \ + "mac2 label,45:mac2 glop,10:djnz glop2010:jp label2045" + +#define AUTOTEST_MACROPAR "macro unemac, param1, param2:defb '{param1}':defb {param2}:mend:unemac grouik,'grouik'" + +#define AUTOTEST_OPCODES "nop::ld bc,#1234::ld (bc),a::inc bc:inc b:dec b:ld b,#12:rlca:ex af,af':add hl,bc:ld a,(bc):dec bc:" \ + "inc c:dec c:ld c,#12:rrca::djnz $:ld de,#1234:ld (de),a:inc de:inc d:dec d:ld d,#12:rla:jr $:" \ + "add hl,de:ld a,(de):dec de:inc e:dec e:ld e,#12:rra::jr nz,$:ld hl,#1234:ld (#1234),hl:inc hl:inc h:" \ + "dec h:ld h,#12:daa:jr z,$:add hl,hl:ld hl,(#1234):dec hl:inc l:dec l:ld l,#12:cpl::jr nc,$:" \ + "ld sp,#1234:ld (#1234),a:inc sp:inc (hl):dec (hl):ld (hl),#12:scf:jr c,$:add hl,sp:ld a,(#1234):" \ + "dec sp:inc a:dec a:ld a,#12:ccf::ld b,b:ld b,c:ld b,d:ld b,e:ld b,h:ld b,l:ld b,(hl):ld b,a:ld c,b:" \ + "ld c,c:ld c,d:ld c,e:ld c,h:ld c,l:ld c,(hl):ld c,a::ld d,b:ld d,c:ld d,d:ld d,e:ld d,h:ld d,l:" \ + "ld d,(hl):ld d,a:ld e,b:ld e,c:ld e,d:ld e,e:ld e,h:ld e,l:ld e,(hl):ld e,a::ld h,b:ld h,c:ld h,d:" \ + "ld h,e:ld h,h:ld h,l:ld h,(hl):ld h,a:ld l,b:ld l,c:ld l,d:ld l,e:ld l,h:ld l,l:ld l,(hl):ld l,a::" \ + "ld (hl),b:ld (hl),c:ld (hl),d:ld (hl),e:ld (hl),h:ld (hl),l:halt:ld (hl),a:ld a,b:ld a,c:ld a,d:" \ + "ld a,e:ld a,h:ld a,l:ld a,(hl):ld a,a::add b:add c:add d:add e:add h:add l:add (hl):add a:adc b:" \ + "adc c:adc d:adc e:adc h:adc l:adc (hl):adc a::sub b:sub c:sub d:sub e:sub h:sub l:sub (hl):sub a:" \ + "sbc b:sbc c:sbc d:sbc e:sbc h:sbc l:sbc (hl):sbc a::and b:and c:and d:and e:and h:and l:and (hl):" \ + "and a:xor b:xor c:xor d:xor e:xor h:xor l:xor (hl):xor a::or b:or c:or d:or e:or h:or l:or (hl):" \ + "or a:cp b:cp c:cp d:cp e:cp h:cp l:cp (hl):cp a::ret nz:pop bc:jp nz,#1234:jp #1234:call nz,#1234:" \ + "push bc:add #12:rst 0:ret z:ret:jp z,#1234:nop:call z,#1234:call #1234:adc #12:rst 8::ret nc:pop de:" \ + "jp nc,#1234:out (#12),a:call nc,#1234:push de:sub #12:rst #10:ret c:exx:jp c,#1234:in a,(#12):" \ + "call c,#1234:nop:sbc #12:rst #18::ret po:pop hl:jp po,#1234:ex (sp),hl:call po,#1234:push hl:" \ + "and #12:rst #20:ret pe:jp (hl):jp pe,#1234:ex de,hl:call pe,#1234:nop:xor #12:rst #28::ret p:pop af:" \ + "jp p,#1234:di:call p,#1234:push af:or #12:rst #30:ret m:ld sp,hl:jp m,#1234:ei:call m,#1234:nop:" \ + "cp #12:rst #38:in b,(c):out (c),b:sbc hl,bc:ld (#1234),bc:neg:retn:im 0:ld i,a:in c,(c):out (c),c:" \ + "adc hl,bc:ld bc,(#1234):reti:ld r,a::in d,(c):out (c),d:sbc hl,de:ld (#1234),de:retn:im 1:ld a,i:" \ + "in e,(c):out (c),e:adc hl,de:ld de,(#1234):im 2:ld a,r::in h,(c):out (c),h:sbc hl,hl:rrd:in l,(c):" \ + "out (c),l:adc hl,hl:rld::in 0,(c):out (c),0:sbc hl,sp:ld (#1234),sp:in a,(c):out (c),a:adc hl,sp:" \ + "ld sp,(#1234)::ldi:cpi:ini:outi:ldd:cpd:ind:outd::ldir:cpir:inir:otir:lddr:cpdr:indr:otdr::rlc b:" \ + "rlc c:rlc d:rlc e:rlc h:rlc l:rlc (hl):rlc a:rrc b:rrc c:rrc d:rrc e:rrc h:rrc l:rrc (hl):rrc a::" \ + "rl b:rl c:rl d:rl e:rl h:rl l:rl (hl):rl a:rr b:rr c:rr d:rr e:rr h:rr l:rr (hl):rr a:sla b:sla c:" \ + "sla d:sla e:sla h:sla l:sla (hl):sla a:sra b:sra c:sra d:sra e:sra h:sra l:sra (hl):sra a::sll b:" \ + "sll c:sll d:sll e:sll h:sll l:sll (hl):sll a:srl b:srl c:srl d:srl e:srl h:srl l:srl (hl):srl a::" \ + "bit 0,b:bit 0,c:bit 0,d:bit 0,e:bit 0,h:bit 0,l:bit 0,(hl):bit 0,a::bit 1,b:bit 1,c:bit 1,d:bit 1,e:" \ + "bit 1,h:bit 1,l:bit 1,(hl):bit 1,a::bit 2,b:bit 2,c:bit 2,d:bit 2,e:bit 2,h:bit 2,l:bit 2,(hl):" \ + "bit 2,a::bit 3,b:bit 3,c:bit 3,d:bit 3,e:bit 3,h:bit 3,l:bit 3,(hl):bit 3,a::bit 4,b:bit 4,c:" \ + "bit 4,d:bit 4,e:bit 4,h:bit 4,l:bit 4,(hl):bit 4,a::bit 5,b:bit 5,c:bit 5,d:bit 5,e:bit 5,h:bit 5,l:" \ + "bit 5,(hl):bit 5,a::bit 6,b:bit 6,c:bit 6,d:bit 6,e:bit 6,h:bit 6,l:bit 6,(hl):bit 6,a::bit 7,b:" \ + "bit 7,c:bit 7,d:bit 7,e:bit 7,h:bit 7,l:bit 7,(hl):bit 7,a::res 0,b:res 0,c:res 0,d:res 0,e:res 0,h:" \ + "res 0,l:res 0,(hl):res 0,a::res 1,b:res 1,c:res 1,d:res 1,e:res 1,h:res 1,l:res 1,(hl):res 1,a::" \ + "res 2,b:res 2,c:res 2,d:res 2,e:res 2,h:res 2,l:res 2,(hl):res 2,a::res 3,b:res 3,c:res 3,d:res 3,e:" \ + "res 3,h:res 3,l:res 3,(hl):res 3,a::res 4,b:res 4,c:res 4,d:res 4,e:res 4,h:res 4,l:res 4,(hl):" \ + "res 4,a::res 5,b:res 5,c:res 5,d:res 5,e:res 5,h:res 5,l:res 5,(hl):res 5,a::res 6,b:res 6,c:" \ + "res 6,d:res 6,e:res 6,h:res 6,l:res 6,(hl):res 6,a::res 7,b:res 7,c:res 7,d:res 7,e:res 7,h:res 7,l:" \ + "res 7,(hl):res 7,a::set 0,b:set 0,c:set 0,d:set 0,e:set 0,h:set 0,l:set 0,(hl):set 0,a::set 1,b:" \ + "set 1,c:set 1,d:set 1,e:set 1,h:set 1,l:set 1,(hl):set 1,a::set 2,b:set 2,c:set 2,d:set 2,e:set 2,h:" \ + "set 2,l:set 2,(hl):set 2,a::set 3,b:set 3,c:set 3,d:set 3,e:set 3,h:set 3,l:set 3,(hl):set 3,a::" \ + "set 4,b:set 4,c:set 4,d:set 4,e:set 4,h:set 4,l:set 4,(hl):set 4,a::set 5,b:set 5,c:set 5,d:set 5,e:" \ + "set 5,h:set 5,l:set 5,(hl):set 5,a::set 6,b:set 6,c:set 6,d:set 6,e:set 6,h:set 6,l:set 6,(hl):" \ + "set 6,a::set 7,b:set 7,c:set 7,d:set 7,e:set 7,h:set 7,l:set 7,(hl):set 7,a::add ix,bc::add ix,de::" \ + "ld ix,#1234:ld (#1234),ix:inc ix:inc xh:dec xh:ld xh,#12:add ix,ix:ld ix,(#1234):dec ix:inc xl:" \ + "dec xl:ld xl,#12::inc (ix+#12):dec (ix+#12):ld (ix+#12),#34:add ix,sp::ld b,xh:ld b,xl:" \ + "ld b,(ix+#12):ld c,xh:ld c,xl:ld c,(ix+#12):::ld d,xh:ld d,xl:ld d,(ix+#12):ld e,xh:ld e,xl:" \ + "ld e,(ix+#12)::ld xh,b:ld xh,c:ld xh,d:ld xh,e:ld xh,xh:ld xh,xl:ld h,(ix+#12):ld xh,a:ld xl,b:" \ + "ld xl,c:ld xl,d:ld xl,e:ld xl,xh:ld xl,xl:ld l,(ix+#12):ld xl,a::ld (ix+#12),b:ld (ix+#12),c:" \ + "ld (ix+#12),d:ld (ix+#12),e:ld (ix+#12),h:ld (ix+#12),l:ld (ix+#12),a:ld a,xh:ld a,xl:" \ + "ld a,(ix+#12)::add xh:add xl:add (ix+#12):adc xh:adc xl:adc (ix+#12)::sub xh:sub xl:sub (ix+#12):" \ + "sbc xh:sbc xl:sbc (ix+#12)::and xh:and xl:and (ix+#12):xor xh:xor xl:xor (ix+#12)::or xh:or xl:" \ + "or (ix+#12):cp xh:cp xl:cp (ix+#12)::pop ix:ex (sp),ix:push ix:jp (ix)::ld sp,ix:::rlc (ix+#12),b:" \ + "rlc (ix+#12),c:rlc (ix+#12),d:rlc (ix+#12),e:rlc (ix+#12),h:rlc (ix+#12),l:rlc (ix+#12):" \ + "rlc (ix+#12),a:rrc (ix+#12),b:rrc (ix+#12),c:rrc (ix+#12),d:rrc (ix+#12),e:rrc (ix+#12),h:" \ + "rrc (ix+#12),l:rrc (ix+#12):rrc (ix+#12),a::rl (ix+#12),b:rl (ix+#12),c:rl (ix+#12),d:rl (ix+#12),e:" \ + "rl (ix+#12),h:rl (ix+#12),l:rl (ix+#12):rl (ix+#12),a:rr (ix+#12),b:rr (ix+#12),c:rr (ix+#12),d:" \ + "rr (ix+#12),e:rr (ix+#12),h:rr (ix+#12),l:rr (ix+#12):rr (ix+#12),a::sla (ix+#12),b:sla (ix+#12),c:" \ + "sla (ix+#12),d:sla (ix+#12),e:sla (ix+#12),h:sla (ix+#12),l:sla (ix+#12):sla (ix+#12),a:" \ + "sra (ix+#12),b:sra (ix+#12),c:sra (ix+#12),d:sra (ix+#12),e:sra (ix+#12),h:sra (ix+#12),l:" \ + "sra (ix+#12):sra (ix+#12),a::sll (ix+#12),b:sll (ix+#12),c:sll (ix+#12),d:sll (ix+#12),e:" \ + "sll (ix+#12),h:sll (ix+#12),l:sll (ix+#12):sll (ix+#12),a:srl (ix+#12),b:srl (ix+#12),c:" \ + "srl (ix+#12),d:srl (ix+#12),e:srl (ix+#12),h:srl (ix+#12),l:srl (ix+#12):srl (ix+#12),a::" \ + "bit 0,(ix+#12):bit 1,(ix+#12):bit 2,(ix+#12):bit 3,(ix+#12):bit 4,(ix+#12):bit 5,(ix+#12):" \ + "bit 6,(ix+#12):bit 7,(ix+#12):bit 0,(ix+#12),d:bit 1,(ix+#12),b:bit 2,(ix+#12),c:bit 3,(ix+#12),d:" \ + "bit 4,(ix+#12),e:bit 5,(ix+#12),h:bit 6,(ix+#12),l:bit 7,(ix+#12),a:::res 0,(ix+#12),b:" \ + "res 0,(ix+#12),c:res 0,(ix+#12),d:res 0,(ix+#12),e:res 0,(ix+#12),h:res 0,(ix+#12),l:res 0,(ix+#12):" \ + "res 0,(ix+#12),a::res 1,(ix+#12),b:res 1,(ix+#12),c:res 1,(ix+#12),d:res 1,(ix+#12),e:" \ + "res 1,(ix+#12),h:res 1,(ix+#12),l:res 1,(ix+#12):res 1,(ix+#12),a::res 2,(ix+#12),b:" \ + "res 2,(ix+#12),c:res 2,(ix+#12),d:res 2,(ix+#12),e:res 2,(ix+#12),h:res 2,(ix+#12),l:res 2,(ix+#12):" \ + "res 2,(ix+#12),a::res 3,(ix+#12),b:res 3,(ix+#12),c:res 3,(ix+#12),d:res 3,(ix+#12),e:" \ + "res 3,(ix+#12),h:res 3,(ix+#12),l:res 3,(ix+#12):res 3,(ix+#12),a::res 4,(ix+#12),b:" \ + "res 4,(ix+#12),c:res 4,(ix+#12),d:res 4,(ix+#12),e:res 4,(ix+#12),h:res 4,(ix+#12),l:" \ + "res 4,(ix+#12):res 4,(ix+#12),a::res 5,(ix+#12),b:res 5,(ix+#12),c:res 5,(ix+#12),d:" \ + "res 5,(ix+#12),e:res 5,(ix+#12),h:res 5,(ix+#12),l:res 5,(ix+#12):res 5,(ix+#12),a::" \ + "res 6,(ix+#12),b:res 6,(ix+#12),c:res 6,(ix+#12),d:res 6,(ix+#12),e:res 6,(ix+#12),h:" \ + "res 6,(ix+#12),l:res 6,(ix+#12):res 6,(ix+#12),a::res 7,(ix+#12),b:res 7,(ix+#12),c:" \ + "res 7,(ix+#12),d:res 7,(ix+#12),e:res 7,(ix+#12),h:res 7,(ix+#12),l:res 7,(ix+#12):" \ + "res 7,(ix+#12),a::set 0,(ix+#12),b:set 0,(ix+#12),c:set 0,(ix+#12),d:set 0,(ix+#12),e:" \ + "set 0,(ix+#12),h:set 0,(ix+#12),l:set 0,(ix+#12):set 0,(ix+#12),a::set 1,(ix+#12),b:" \ + "set 1,(ix+#12),c:set 1,(ix+#12),d:set 1,(ix+#12),e:set 1,(ix+#12),h:set 1,(ix+#12),l:" \ + "set 1,(ix+#12):set 1,(ix+#12),a::set 2,(ix+#12),b:set 2,(ix+#12),c:set 2,(ix+#12),d:" \ + "set 2,(ix+#12),e:set 2,(ix+#12),h:set 2,(ix+#12),l:set 2,(ix+#12):set 2,(ix+#12),a::" \ + "set 3,(ix+#12),b:set 3,(ix+#12),c:set 3,(ix+#12),d:set 3,(ix+#12),e:set 3,(ix+#12),h:" \ + "set 3,(ix+#12),l:set 3,(ix+#12):set 3,(ix+#12),a::set 4,(ix+#12),b:set 4,(ix+#12),c:" \ + "set 4,(ix+#12),d:set 4,(ix+#12),e:set 4,(ix+#12),h:set 4,(ix+#12),l:set 4,(ix+#12):" \ + "set 4,(ix+#12),a::set 5,(ix+#12),b:set 5,(ix+#12),c:set 5,(ix+#12),d:set 5,(ix+#12),e:" \ + "set 5,(ix+#12),h:set 5,(ix+#12),l:set 5,(ix+#12):set 5,(ix+#12),a::set 6,(ix+#12),b:" \ + "set 6,(ix+#12),c:set 6,(ix+#12),d:set 6,(ix+#12),e:set 6,(ix+#12),h:set 6,(ix+#12),l:" \ + "set 6,(ix+#12):set 6,(ix+#12),a::set 7,(ix+#12),b:set 7,(ix+#12),c:set 7,(ix+#12),d:" \ + "set 7,(ix+#12),e:set 7,(ix+#12),h:set 7,(ix+#12),l:set 7,(ix+#12):set 7,(ix+#12),a::add iy,bc::" \ + "add iy,de::ld iy,#1234:ld (#1234),iy:inc iy:inc yh:dec yh:ld yh,#12:add iy,iy:ld iy,(#1234):dec iy:" \ + "inc yl:dec yl:ld yl,#12::inc (iy+#12):dec (iy+#12):ld (iy+#12),#34:add iy,sp::ld b,yh:ld b,yl:" \ + "ld b,(iy+#12):ld c,yh:ld c,yl:ld c,(iy+#12):::ld d,yh:ld d,yl:ld d,(iy+#12):ld e,yh:ld e,yl:" \ + "ld e,(iy+#12)::ld yh,b:ld yh,c:ld yh,d:ld yh,e:ld yh,yh:ld yh,yl:ld h,(iy+#12):ld yh,a:ld yl,b:" \ + "ld yl,c:ld yl,d:ld yl,e:ld yl,yh:ld yl,yl:ld l,(iy+#12):ld yl,a::ld (iy+#12),b:ld (iy+#12),c:" \ + "ld (iy+#12),d:ld (iy+#12),e:ld (iy+#12),h:ld (iy+#12),l:ld (iy+#12),a:ld a,yh:ld a,yl:" \ + "ld a,(iy+#12)::add yh:add yl:add (iy+#12):adc yh:adc yl:adc (iy+#12)::sub yh:sub yl:" \ + "sub (iy+#12):sbc yh:sbc yl:sbc (iy+#12)::and yh:and yl:and (iy+#12):xor yh:xor yl:xor (iy+#12)::" \ + "or yh:or yl:or (iy+#12):cp yh:cp yl:cp (iy+#12)::pop iy:ex (sp),iy:push iy:jp (iy)::ld sp,iy::" \ + "rlc (iy+#12),b:rlc (iy+#12),c:rlc (iy+#12),d:rlc (iy+#12),e:rlc (iy+#12),h:rlc (iy+#12),l:" \ + "rlc (iy+#12):rlc (iy+#12),a:rrc (iy+#12),b:rrc (iy+#12),c:rrc (iy+#12),d:rrc (iy+#12),e:" \ + "rrc (iy+#12),h:rrc (iy+#12),l:rrc (iy+#12):rrc (iy+#12),a::rl (iy+#12),b:rl (iy+#12),c:" \ + "rl (iy+#12),d:rl (iy+#12),e:rl (iy+#12),h:rl (iy+#12),l:rl (iy+#12):rl (iy+#12),a:rr (iy+#12),b:" \ + "rr (iy+#12),c:rr (iy+#12),d:rr (iy+#12),e:rr (iy+#12),h:rr (iy+#12),l:rr (iy+#12):rr (iy+#12),a::" \ + "sla (iy+#12),b:sla (iy+#12),c:sla (iy+#12),d:sla (iy+#12),e:sla (iy+#12),h:sla (iy+#12),l:" \ + "sla (iy+#12):sla (iy+#12),a:sra (iy+#12),b:sra (iy+#12),c:sra (iy+#12),d:sra (iy+#12),e:" \ + "sra (iy+#12),h:sra (iy+#12),l:sra (iy+#12):sra (iy+#12),a::sll (iy+#12),b:sll (iy+#12),c:" \ + "sll (iy+#12),d:sll (iy+#12),e:sll (iy+#12),h:sll (iy+#12),l:sll (iy+#12):sll (iy+#12),a:" \ + "srl (iy+#12),b:srl (iy+#12),c:srl (iy+#12),d:srl (iy+#12),e:srl (iy+#12),h:srl (iy+#12),l:" \ + "srl (iy+#12):srl (iy+#12),a::bit 0,(iy+#12):bit 1,(iy+#12):bit 2,(iy+#12):bit 3,(iy+#12):" \ + "bit 4,(iy+#12):bit 5,(iy+#12):bit 6,(iy+#12):bit 7,(iy+#12)::res 0,(iy+#12),b:res 0,(iy+#12),c:" \ + "res 0,(iy+#12),d:res 0,(iy+#12),e:res 0,(iy+#12),h:res 0,(iy+#12),l:res 0,(iy+#12):" \ + "res 0,(iy+#12),a::res 1,(iy+#12),b:res 1,(iy+#12),c:res 1,(iy+#12),d:res 1,(iy+#12),e:" \ + "res 1,(iy+#12),h:res 1,(iy+#12),l:res 1,(iy+#12):res 1,(iy+#12),a::res 2,(iy+#12),b:" \ + "res 2,(iy+#12),c:res 2,(iy+#12),d:res 2,(iy+#12),e:res 2,(iy+#12),h:res 2,(iy+#12),l:" \ + "res 2,(iy+#12):res 2,(iy+#12),a::res 3,(iy+#12),b:res 3,(iy+#12),c:res 3,(iy+#12),d:" \ + "res 3,(iy+#12),e:res 3,(iy+#12),h:res 3,(iy+#12),l:res 3,(iy+#12):res 3,(iy+#12),a::" \ + "res 4,(iy+#12),b:res 4,(iy+#12),c:res 4,(iy+#12),d:res 4,(iy+#12),e:res 4,(iy+#12),h:" \ + "res 4,(iy+#12),l:res 4,(iy+#12):res 4,(iy+#12),a::res 5,(iy+#12),b:res 5,(iy+#12),c:" \ + "res 5,(iy+#12),d:res 5,(iy+#12),e:res 5,(iy+#12),h:res 5,(iy+#12),l:res 5,(iy+#12):" \ + "res 5,(iy+#12),a::res 6,(iy+#12),b:res 6,(iy+#12),c:res 6,(iy+#12),d:res 6,(iy+#12),e:" \ + "res 6,(iy+#12),h:res 6,(iy+#12),l:res 6,(iy+#12):res 6,(iy+#12),a::res 7,(iy+#12),b:" \ + "res 7,(iy+#12),c:res 7,(iy+#12),d:res 7,(iy+#12),e:res 7,(iy+#12),h:res 7,(iy+#12),l:" \ + "res 7,(iy+#12):res 7,(iy+#12),a::set 0,(iy+#12),b:set 0,(iy+#12),c:set 0,(iy+#12),d:" \ + "set 0,(iy+#12),e:set 0,(iy+#12),h:set 0,(iy+#12),l:set 0,(iy+#12):set 0,(iy+#12),a::" \ + "set 1,(iy+#12),b:set 1,(iy+#12),c:set 1,(iy+#12),d:set 1,(iy+#12),e:set 1,(iy+#12),h:" \ + "set 1,(iy+#12),l:set 1,(iy+#12):set 1,(iy+#12),a::set 2,(iy+#12),b:set 2,(iy+#12),c:" \ + "set 2,(iy+#12),d:set 2,(iy+#12),e:set 2,(iy+#12),h:set 2,(iy+#12),l:set 2,(iy+#12):" \ + "set 2,(iy+#12),a::set 3,(iy+#12),b:set 3,(iy+#12),c:set 3,(iy+#12),d:set 3,(iy+#12),e:" \ + "set 3,(iy+#12),h:set 3,(iy+#12),l:set 3,(iy+#12):set 3,(iy+#12),a::set 4,(iy+#12),b:" \ + "set 4,(iy+#12),c:set 4,(iy+#12),d:set 4,(iy+#12),e:set 4,(iy+#12),h:set 4,(iy+#12),l:" \ + "set 4,(iy+#12):set 4,(iy+#12),a::set 5,(iy+#12),b:set 5,(iy+#12),c:set 5,(iy+#12),d:" \ + "set 5,(iy+#12),e:set 5,(iy+#12),h:set 5,(iy+#12),l:set 5,(iy+#12):set 5,(iy+#12),a::" \ + "set 6,(iy+#12),b:set 6,(iy+#12),c:set 6,(iy+#12),d:set 6,(iy+#12),e:set 6,(iy+#12),h:" \ + "set 6,(iy+#12),l:set 6,(iy+#12):set 6,(iy+#12),a::set 7,(iy+#12),b:set 7,(iy+#12),c:" \ + "set 7,(iy+#12),d:set 7,(iy+#12),e:set 7,(iy+#12),h:set 7,(iy+#12),l:set 7,(iy+#12):" \ + "set 7,(iy+#12),a:" + +#define AUTOTEST_LABNUM "mavar=67:label{mavar}truc:ld hl,7+2*label{mavar}truc:mnt=1234567:lab2{mavar}{mnt}:" \ + "ld de,lab2{mavar}{mnt}:lab3{mavar}{mnt}h:ld de,lab3{mavar}{mnt}h" + +#define AUTOTEST_EQUNUM "mavar = 9:monlabel{mavar+5}truc:unalias{mavar+5}heu equ 50:autrelabel{unalias14heu}:ld hl,autrelabel50" + +#define AUTOTEST_EQUDOLLAR " ld hl,une_equ: ld de,deux_equ: ldir: une_equ equ $+2: deux_equ equ $+4: defw 1: preums: defw 2: deuze: defw 3,4,5,6: assert une_equ == preums: assert deux_equ == deuze" + + +#define AUTOTEST_DELAYNUM "macro test label: dw {label}: endm: repeat 3, idx:idx2 = idx-1:" \ + " test label_{idx2}: rend:repeat 3, idx:label_{idx-1}:nop:rend" + +#define AUTOTEST_STRUCT "org #1000:label1 :struct male:age defb 0:height defb 0:endstruct:struct female:" \ + "age defb 0:height defb 0:endstruct:struct couple:struct male husband:" \ + "struct female wife:endstruct:if $-label1!=0:stop:endif:ld a,(ix+couple.wife.age):" \ + "ld bc,couple:ld bc,{sizeof}couple:struct couple mycouple:" \ + "if mycouple.husband != mycouple.husband.age:stop:endif:ld hl,mycouple:" \ + "ld hl,mycouple.wife.age:ld bc,{sizeof}mycouple:macro cmplastheight p1:" \ + "ld hl,@mymale.height:ld a,{p1}:cp (hl):ld bc,{sizeof}@mymale:ld hl,@mymale:ret:" \ + "struct male @mymale:mend:cmplastheight 5:cmplastheight 3:nop" + +#define AUTOTEST_STRUCT2 "struct bite: preums defb 0: deuze defw 1: troize defs 10: endstruct:" \ + " if {sizeof}bite.preums!=1 || {sizeof}bite.deuze!=2 || {sizeof}bite.troize!=10: stop: endif: nop " + +#define AUTOTEST_REPEAT "ce=100:repeat 2,ce:repeat 5,cx:repeat 5,cy:defb cx*cy:rend:rend:rend:assert cx==6 && cy==6 && ce==3:" \ + "cpt=0:repeat:cpt=cpt+1:until cpt>4:assert cpt==5" + +#define AUTOTEST_REPEATKO "repeat 5:nop" + +#define AUTOTEST_WHILEKO "while 5:nop" + +#define AUTOTEST_TICKER "repeat 2: ticker start, mc:out (0),a:out (c),a:out (c),h:out (c),0:ticker stop, mc:if mc!=15:ld hl,bite:else:nop:endif:rend" + +#define AUTOTEST_ORG "ORG #8000,#1000:defw $:ORG $:defw $" + +#define AUTOTEST_BANKORG "bank 0:nop:org #5:nop:bank 1:unevar=10:bank 0:assert $==6:ret:bank 1:assert $==0:bank 0:assert $==7" + +#define AUTOTEST_VAREQU "label1 equ #C000:label2 equ (label1*2)/16:label3 equ label1-label2:label4 equ 15:var1=50*3+2:var2=12*label1:var3=label4-8:var4=label2:nop" + +#define AUTOTEST_FORMAT "hexa=#12A+$23B+45Ch+0x56D:deci=123.45+-78.54*2-(7-7)*2:bina=0b101010+1010b-%1111:assert hexa==3374 && deci==-33.63 && bina==37:nop" + +#define AUTOTEST_CHARSET "charset 'abcde',0:defb 'abcde':defb 'a','b','c','d','e':defb 'a',1*'b','c'*1,1*'d','e'*1:charset:" \ + "defb 'abcde':defb 'a','b','c','d','e':defb 'a',1*'b','c'*1,1*'d','e'*1" + +#define AUTOTEST_CHARSET2 "charset 97,97+26,0:defb 'roua':charset:charset 97,10:defb 'roua':charset 'o',5:defb 'roua':charset 'ou',6:defb 'roua'" + +#define AUTOTEST_NOCODE "let monorg=$:NoCode:Org 0:Element1 db 0:Element2 dw 3:Element3 ds 50:Element4 defb 'rdd':Org 0:pouet defb 'nop':" \ + "Code:Org monorg:cpt=$+element2+element3+element4:defs cpt,0" + +#define AUTOTEST_LZSEGMENT "org #100:debut:jr nz,zend:lz48:repeat 128:nop:rend:lzclose:jp zend:lz48:repeat 2:dec a:jr nz,@next:ld a,5:@next:jp debut:rend:" \ + "lzclose:zend" + +#define AUTOTEST_MULTILZ "bank: jr suivant: lz48: defs 100,#FF: lzclose: suivant jr lafin: lz49: defs 100,#FF: lzclose: lafin: bank: jr preums: " \ + " preums jr suivant2: lzapu: defs 100,#FF: lzclose: suivant2 jr lafin2: lzexo: defs 100,#FF: lzclose: lafin2 " + +#define AUTOTEST_MULTILZORG " tabeul: defw script0: defw script1: defw script2: " \ + "script0: org #4000,$: lz48: start1: jr end1: defs 100: djnz start1: end1: lzclose: " \ + "org $: script1: org #4000,$: lz49: start2: jr end2: defs 100: djnz start2: end2: lzclose: " \ + "org $: script2: org #4000,$: lz49: start3: jr end3: defs 100: djnz start3: end3: lzclose: " \ + "org $: ei: ret " + +#define AUTOTEST_LZDEFERED "lz48:defs 20:lzclose:defb $" + + +#define AUTOTEST_PAGETAG "bankset 0:org #5000:label1:bankset 1:org #9000:label2:bankset 2:" \ + "assert {page}label1==0x7FC0:assert {page}label2==0x7FC6:assert {pageset}label1==#7FC0:assert {pageset}label2==#7FC2:nop" + +#define AUTOTEST_PAGETAG2 "bankset 0:call maroutine:bank 4:org #C000:autreroutine:nop:" \ + "ret:bank 5:org #8000:maroutine:ldir:ret:bankset 2:org #9000:troize:nop:" \ + "assert {page}maroutine==#7FC5:assert {pageset}maroutine==#7FC2:assert {page}autreroutine==#7FC4:" \ + "assert {pageset}autreroutine==#7FC2:assert {page}troize==#7FCE:assert {pageset}troize==#7FCA" + +#define AUTOTEST_PAGETAG3 "buildsna:bank 2:assert {bank}$==2:assert {page}$==0x7FC0:assert {pageset}$==#7FC0:" \ + "bankset 1:org #4000:assert {bank}$==5:assert {page}$==0x7FC5:assert {pageset}$==#7FC2" + +#define AUTOTEST_SWITCH "mavar=4:switch mavar:case 1:nop:case 4:defb 4:case 3:defb 3:break:case 2:nop:case 4:defb 4:endswitch" + +#define AUTOTEST_PREPRO0 "\n\n\n\n;bitch\n\nnop\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nxor a\n\n\n\n\n\n\n\n\n\n\n\n" + +#define AUTOTEST_PREPRO1 " macro DEBUG_INK0, coul: out (c), a: endm: ifndef NDEBUG:DEBUG_BORDER_NOPS = 0: endif" + +#define AUTOTEST_PREPRO2 " nop : mycode other tartine ldir : defw tartine,other, mycode : assert tartine==other && other==mycode && mycode==1 && $==9" + +#define AUTOTEST_PREPRO3 "nop\n \n /* test ' ici */\n nop /* retest */ 5\n /* bonjour\n prout\n caca\n pipi */" \ + " nop\n nop /* nop */ : nop\n ; grouik /*\n \n /* ; pouet */ ld hl,#2121\n " + +#define AUTOTEST_PREPRO4 "glop=0\n nop ; glop=1\n assert glop==0\n nop\n glop=0\n nop // glop=1\n assert glop==0\n nop\n glop=0 : /* glop=1 */ nop\n" \ + "assert glop==0\n nop\n \n glop=0 : /* glop=1 // */ nop\n assert glop==0\n nop\n glop=0 : /* glop=1 ; */ nop\n" \ + "assert glop==0\n nop\n glop=0 ; /* glop=1\n nop // glop=2 /*\n assert glop==0\n nop\n" + +#define AUTOTEST_PROXIM "routine:.step1:jp .step2:.step2:jp .step1:deuze:nop:.step1:djnzn .step1:djnz routine.step2" + +#define AUTOTEST_TAGPRINT "unevar=12:print 'trucmuche{unevar}':print '{unevar}':print '{unevar}encore','pouet{unevar}{unevar}':ret" + +#define AUTOTEST_TAGFOLLOW "ret:uv=1234567890:unlabel_commeca_{uv} equ pouetpouetpouettroulala:pouetpouetpouettroulala:assert unlabel_commeca_{uv}>0" + +#define AUTOTEST_TAGREALLOC "zoomscroller_scroller_height equ 10: another_super_long_equ equ 256: pinouille_super_long_useless_equ equ 0: " \ + "zz equ 1111111111: org #100: repeat zoomscroller_scroller_height,idx: " \ + "zoomscroller_buffer_line_{idx-1}_{pinouille_super_long_useless_equ} nop: zoomscroller_buffer_line_{idx-1}_{zz} nop: " \ + "rend: align 256: repeat zoomscroller_scroller_height,idx: zoomscroller_buffer_line_{idx-1}_{pinouille_super_long_useless_equ}_duplicate nop: " \ + "zoomscroller_buffer_line_{idx-1}_{zz}_duplicate nop: rend: repeat zoomscroller_scroller_height, line: idx = line - 1: " \ + "assert zoomscroller_buffer_line_{idx}_{pinouille_super_long_useless_equ} + another_super_long_equ == "\ + "zoomscroller_buffer_line_{idx}_{pinouille_super_long_useless_equ}_duplicate: " \ + "assert zoomscroller_buffer_line_{idx}_{zz} + another_super_long_equ == zoomscroller_buffer_line_{idx}_{zz}_duplicate: rend" + +#define AUTOTEST_DEFUSED "ld hl,labelused :ifdef labelused:fail 'labelexiste':endif:ifndef labelused:else:fail 'labelexiste':endif:" \ + "ifnused labelused:fail 'labelused':endif:ifused labelused:else:fail 'labelused':endif:labelused" + +#define AUTOTEST_ALIGN "org 0:nop: align 64: defb 64: align 128: defb 128: align 256: defb 255 " + +#define AUTOTEST_CONFINE "org 0: nop: org 250: confine 10: defb #aa: org 500: confine 12: defb #bb: assert $<512 " + +#define AUTOTEST_SAVEINVALID0 "repeat 256,x : defb x-1 : rend : save 'rasmoutput.bin',0,$" + +#define AUTOTEST_SAVEINVALID1 "nop : save'gruik',20,-100" + +#define AUTOTEST_SAVEINVALID2 "nop : save'gruik',-20,100" + +#define AUTOTEST_SAVEINVALID3 "nop : save'gruik',40000,30000" + +#define AUTOTEST_MACROPROX " macro unemacro: nop: endm: global_label: ld hl, .table: .table" + +#define AUTOTEST_MACRO_CONF01 " nop: macro label1: nop: mend: macro label1: nop: mend:" +#define AUTOTEST_MACRO_CONF02 " label1=0: macro label1: nop: mend: nop:" +#define AUTOTEST_MACRO_CONF03 " label1 equ #100: macro label1: nop: mend: nop:" +#define AUTOTEST_MACRO_CONF04 " label1 nop: macro label1: nop: mend: nop" + +#define AUTOTEST_PROXBACK " macro grouik: @truc djnz @truc: .unprox djnz .unprox: mend:" \ + "ld b,2: unglobal nop: djnz unglobal: ld b,2: .unprox nop: djnz .unprox: beforelocal=$ :" \ + "repeat 2: @unlocal: ld b,2: .unprox nop: djnz .unprox: grouik : djnz .unprox : rend: assert .unprox < beforelocal : nop" +#define AUTOTEST_LOCAPROX "repeat 1: @label nop: .prox nop: @label2 nop: djnz @label.prox: rend" + +#define AUTOTEST_QUOTES "defb 'rdd':str 'rdd':charset 'rd',0:defb '\\r\\d':str '\\r\\d'" + +#define AUTOTEST_NEGATIVE "ld a,-5: ld bc,-0x3918:ld de,0+-#3918:ld de,-#3918:var1=-5+6:var2=-#3918+#3919:assert var1+var2==2" + +#define AUTOTEST_FORMULA1 "a=5:b=2:assert int(a/b)==3:assert !a+!b==0:a=a*100:b=b*100:assert a*b==100000:ld hl,a*b-65536:a=123+-5*(-6/2)-50*2<<1" + +#define AUTOTEST_FORMULA2 "vala= (0.5+(4*0.5))*6:valb= int((0.5+(4*0.5))*6):nop:if vala!=valb:push erreur:endif" + +#define AUTOTEST_SHIFTMAX "a=45: a=a>>256: assert a==0:nop" + +#define AUTOTEST_FRAC "mavar=frac(5.5):assert mavar==0.5:assert frac(6.6)==0.6:assert frac(1.1)==0.1:assert frac(1)==0:assert frac(100000)==0:nop" + +#define AUTOTEST_RND "repeat:glop=rnd(20):until glop==10:nop" + +/* test override control between bank and bankset in snapshot mode + temp workspace */ +#define AUTOTEST_BANKSET "buildsna:bank 0:nop:bank 1:nop:bank:nop:bank 2:nop:bank 3:nop:bankset 1:nop:bank 8:nop:bank 9:nop:bank 10:nop:bank 11:nop" + +#define AUTOTEST_LIMITOK "org #100:limit #102:nop:limit #103:ld a,0:protect #105,#107:limit #108:xor a:org $+3:inc a" + +#define AUTOTEST_LIMITKO "limit #100:org #100:add ix,ix" + +#define AUTOTEST_DEFS "defs 256,0" + +#define AUTOTEST_LIMIT03 "limit -1 : nop" +#define AUTOTEST_LIMIT04 "limit #10001 : nop" +#define AUTOTEST_LIMIT05 "org #FFFF : ldir" +#define AUTOTEST_LIMIT06 "org #FFFF : nop" + +#define AUTOTEST_LIMIT07 "org #ffff : Start: equ $ : di : ld hl,#c9fb : ld (#38),hl" + +#define AUTOTEST_DELAYED_RUN "run _start:nop:_start nop" + +#define AUTOTEST_INHIBITION "if 0:ifused truc:ifnused glop:ifdef bidule:ifndef machin:ifnot 1:nop:endif:nop:else:nop:endif:endif:endif:endif:endif" + +#define AUTOTEST_LZ4 "lz4:repeat 10:nop:rend:defb 'roudoudoudouoneatxkjhgfdskljhsdfglkhnopnopnopnop':lzclose" + +#define AUTOTEST_INCBIN1 "incbin 'autotest_include.raw'" +#define AUTOTEST_INCBIN2 "incbin 'autotest_include.raw',1000" +#define AUTOTEST_INCBIN3 "incbin 'autotest_include.raw',0,1000" + +#define AUTOTEST_LZ4_A "lz4 : incbin 'autotest_include.raw' : lzclose" +#define AUTOTEST_LZ4_B "inclz4 'autotest_include.raw'" +#define AUTOTEST_LZ4_C "inclz4 'autotest_include.raw',100" +#define AUTOTEST_LZ4_D "lz4 : incbin 'autotest_include.raw',100 : lzclose" +#define AUTOTEST_LZ4_E "inclz4 'autotest_include.raw',0,1000" +#define AUTOTEST_LZ4_F "lz4 : incbin'autotest_include.raw',0,1000 : lzclose" + +#define AUTOTEST_LZ48_A "lz48 : incbin 'autotest_include.raw' : lzclose" +#define AUTOTEST_LZ48_B "incl48 'autotest_include.raw'" +#define AUTOTEST_LZ48_C "incl48 'autotest_include.raw',100" +#define AUTOTEST_LZ48_D "lz48 : incbin 'autotest_include.raw',100 : lzclose" +#define AUTOTEST_LZ48_E "incl48 'autotest_include.raw',0,1000" +#define AUTOTEST_LZ48_F "lz48 : incbin'autotest_include.raw',0,1000 : lzclose" + +#define AUTOTEST_LZ49_A "lz49 : incbin 'autotest_include.raw' : lzclose" +#define AUTOTEST_LZ49_B "incl49 'autotest_include.raw'" +#define AUTOTEST_LZ49_C "incl49 'autotest_include.raw',100" +#define AUTOTEST_LZ49_D "lz49 : incbin 'autotest_include.raw',100 : lzclose" +#define AUTOTEST_LZ49_E "incl49 'autotest_include.raw',0,1000" +#define AUTOTEST_LZ49_F "lz49 : incbin'autotest_include.raw',0,1000 : lzclose" + +#define AUTOTEST_LZAPU_A "lzapu : incbin 'autotest_include.raw' : lzclose" +#define AUTOTEST_LZAPU_B "incapu 'autotest_include.raw'" +#define AUTOTEST_LZAPU_C "incapu 'autotest_include.raw',100" +#define AUTOTEST_LZAPU_D "lzapu : incbin 'autotest_include.raw',100 : lzclose" +#define AUTOTEST_LZAPU_E "incapu 'autotest_include.raw',0,1000" +#define AUTOTEST_LZAPU_F "lzapu : incbin'autotest_include.raw',0,1000 : lzclose" + +#define AUTOTEST_LZSA2_A "lzsa2 : incbin 'autotest_include.raw' : lzclose" +#define AUTOTEST_LZSA2_Abis "lzsa2 2 : incbin 'autotest_include.raw' : lzclose" +#define AUTOTEST_LZSA2_B "inclzsa2 'autotest_include.raw'" +#define AUTOTEST_LZSA2_C "inclzsa2 'autotest_include.raw',100" +#define AUTOTEST_LZSA2_D "lzsa2 : incbin 'autotest_include.raw',100 : lzclose" +#define AUTOTEST_LZSA2_E "inclzsa2 'autotest_include.raw',0,1000" +#define AUTOTEST_LZSA2_F "lzsa2 : incbin'autotest_include.raw',0,1000 : lzclose" + +#define AUTOTEST_LZSA1_A "lzsa1 : incbin 'autotest_include.raw' : lzclose" +#define AUTOTEST_LZSA1_Abis "lzsa1 2 : incbin 'autotest_include.raw' : lzclose" +#define AUTOTEST_LZSA1_B "inclzsa1 'autotest_include.raw'" +#define AUTOTEST_LZSA1_C "inclzsa1 'autotest_include.raw',100" +#define AUTOTEST_LZSA1_D "lzsa1 : incbin 'autotest_include.raw',100 : lzclose" +#define AUTOTEST_LZSA1_E "inclzsa1 'autotest_include.raw',0,1000" +#define AUTOTEST_LZSA1_F "lzsa1 : incbin'autotest_include.raw',0,1000 : lzclose" + +#define AUTOTEST_LZEXO_A "lzexo : incbin 'autotest_include.raw' : lzclose" +#define AUTOTEST_LZEXO_B "incexo 'autotest_include.raw'" +#define AUTOTEST_LZEXO_C "incexo 'autotest_include.raw',100" +#define AUTOTEST_LZEXO_D "lzexo : incbin 'autotest_include.raw',100 : lzclose" +#define AUTOTEST_LZEXO_E "incexo 'autotest_include.raw',0,1000" +#define AUTOTEST_LZEXO_F "lzexo : incbin'autotest_include.raw',0,1000 : lzclose" + +#define AUTOTEST_LZX7_A "lzx7 : incbin 'autotest_include.raw' : lzclose" +#define AUTOTEST_LZX7_B "inczx7 'autotest_include.raw'" +#define AUTOTEST_LZX7_C "inczx7 'autotest_include.raw',100" +#define AUTOTEST_LZX7_D "lzx7 : incbin 'autotest_include.raw',100 : lzclose" +#define AUTOTEST_LZX7_E "inczx7 'autotest_include.raw',0,1000" +#define AUTOTEST_LZX7_F "lzx7 : incbin'autotest_include.raw',0,1000 : lzclose" + +#define AUTOTEST_LZX0_A "lzx0 : incbin 'autotest_include.raw' : lzclose" +#define AUTOTEST_LZX0_B "inczx0 'autotest_include.raw'" +#define AUTOTEST_LZX0_C "inczx0 'autotest_include.raw',100" +#define AUTOTEST_LZX0_D "lzx0 : incbin 'autotest_include.raw',100 : lzclose" +#define AUTOTEST_LZX0_E "inczx0 'autotest_include.raw',0,1000" +#define AUTOTEST_LZX0_F "lzx0 : incbin'autotest_include.raw',0,1000 : lzclose" + +#define AUTOTEST_LZX0B_A "lzx0b : incbin 'autotest_include.raw' : lzclose" +#define AUTOTEST_LZX0B_B "inczx0b 'autotest_include.raw'" +#define AUTOTEST_LZX0B_C "inczx0b 'autotest_include.raw',100" +#define AUTOTEST_LZX0B_D "lzx0b : incbin 'autotest_include.raw',100 : lzclose" +#define AUTOTEST_LZX0B_E "inczx0b 'autotest_include.raw',0,1000" +#define AUTOTEST_LZX0B_F "lzx0b : incbin'autotest_include.raw',0,1000 : lzclose" + + +#define AUTOTEST_MAXERROR "repeat 20:aglapi:rend:nop" + +#define AUTOTEST_REAL "defr 0,0.5,-0.5,43.375,3.14159265,-0.25,0.9994433,0.9994434,-0.9994433,-0.9994434,0.1234567,1.2345678,0.00007" + +#define AUTOTEST_ENHANCED_LD "ld h,(ix+11): ld l,(ix+10): ld h,(iy+21): ld l,(iy+20): ld b,(ix+11): ld c,(ix+10):" \ + "ld b,(iy+21): ld c,(iy+20): ld d,(ix+11): ld e,(ix+10): ld d,(iy+21): ld e,(iy+20): ld hl,(ix+10): " \ + "ld hl,(iy+20):ld bc,(ix+10):ld bc,(iy+20): ld de,(ix+10):ld de,(iy+20)" + +#define AUTOTEST_ENHANCED_PUSHPOP "push bc,de,hl,ix,iy,af:pop hl,bc,de,iy,ix,af:nop 2:" \ + "push bc:push de:push hl:push ix:push iy:push af:"\ + "pop hl:pop bc:pop de:pop iy:pop ix:pop af:nop:nop" +#define AUTOTEST_ENHANCED_LD2 "ld (ix+0),hl: ld (ix+0),de: ld (ix+0),bc: ld (iy+0),hl: ld (iy+0),de: ld (iy+0),bc:"\ +"ld (ix+1),h: ld (ix+0),l: ld (ix+1),d: ld (ix+0),e: ld (ix+1),b: ld (ix+0),c: ld (iy+1),h: ld (iy+0),l: ld (iy+1),d: ld (iy+0),e: ld (iy+1),b: ld (iy+0),c" + +#define AUTOTEST_ENHANCED_LD3 "ld bc,ix : ld bc,iy : ld de,ix : ld de,iy : ld ix,bc : ld ix,de : ld iy,bc : ld iy,de:"\ + "ld b,hx : ld c,lx : ld b,hy : ld c,ly : ld d,hx : ld e,lx : ld d,hy : ld e,ly :"\ + "ld hx,b : ld lx,c : ld hx,d : ld lx,e : ld hy,b : ld ly,c : ld hy,d : ld ly,e" + +#define AUTOTEST_INHIBITION2 "ifdef roudoudou:macro glop bank,page,param:ld a,{bank}:ld hl,{param}{bank}:if {bank}:nop:else:exx:" \ + "endif::switch {param}:nop:case 4:nop:case {param}:nop:default:nop:break:endswitch:endif:defb 'coucou'" + +#define AUTOTEST_INHIBITIONMAX "roudoudou:ifndef roudoudou:if pouet:macro glop bank,page,param:ifdef nanamouskouri:ld hl,{param}{bank}:"\ + "elseif aglapi:exx:endif:if {bank}:nop:elseif {grouik}:exx:endif:switch {bite}:nop:case {nichon}:nop:default:nop:break:endswitch:else:"\ + "ifnot {jojo}:exx:endif:endif:else:defb 'coucou':endif" + +#define AUTOTEST_NOEXPORT "unlabel nop:.unlocal nop:unevar=5:unequ equ 10:noexport unlabel, .unlocal, "\ + "unlabel.unlocal, unevar, unequ:enoexport unlabel, .unlocal, unlabel.unlocal, unevar, unequ" + +#define AUTOTEST_UNDERVAR "coucou nop:_coucou nop:_mavar=5:jr _coucou+_mavar:print _mavar" + +#define AUTOTEST_CODESKIP "org #100: nop: old_dollar=$: nocode: defs 10: assert $==old_dollar+10: code: "\ + "assert $==old_dollar+10: org #200: nop: old_dollar=$: nocode: defs 10: assert $==old_dollar+10: code skip: assert $==old_dollar" + +#define AUTOTEST_EMBEDDED_ERRORS "nop : rien : rien : rien : glop nop : glapi nop" + +#define AUTOTEST_EMBEDDED_LABELS " disarkCounter = 0:MACRO dkps:PLY_AKG_DisarkPointerRegionStart_{disarkCounter}:ENDM" \ + ":MACRO dkpe\nPLY_AKG_DisarkPointerRegionEnd_{disarkCounter}:\ndisarkCounter = disarkCounter + 1:ENDM:\ndkps\ndkpe\ndkps" + +#define AUTOTEST_TAGLOOP "tab1 = #100:tab2 = #200:tab3 = #300:macro genreg channel,psg:label{channel} EQU tab{psg} + channeloffset:"\ + "endm:channel=1:while channel <= 9:psg=floor(((channel-1)/3)+1):channeloffset=((channel-1) % 3)*2:"\ + "genreg {channel},{psg}:channel=channel+1:wend:assert LABEL5==#0202:assert LABEL6==#0204:assert LABEL7==#0300:"\ + "assert LABEL8==#0302:nop" + +#define AUTOTEST_PLUSCOLOR " myval=0x123 : assert getr(myval)==2 : assert getb(myval)==3 : assert getg(myval)==1 : assert getv(myval)==1" \ + " : assert setr(2)+setv(1)+setb(3)==0x123 : assert setv(-2)==setv(0) && setb(220)==setb(15) : nop " + +#define AUTOTEST_ASSERT " macro zem,nom,adr: overflow equ $-{adr}: assert $<{adr},{nom}: nop: mend: zem 'bidule',#2FFF :" \ + " macro zem2,nom,adr: overflow2 equ $-{adr}: assert $<{adr},{nom},{adr},overflow2: nop: mend: zem2 'bidule',#2FFF :" \ + " macro zem3,nom,adr: overflow3 equ $-{adr}: assert $<{adr},{nom},{hex}{adr},overflow3: nop: mend: zem3 'bidule',#2FFF " + +#define AUTOTEST_OPERATORASSIGN "a=5 : a*=3 : assert a==15 : a/=5 : assert a==3 : a&=2 : assert a==2 : a+=10 : assert a==12 : "\ + "a-=3 : assert a==9 : a%=5 : assert a==4 : a|=1 : assert a==5 : a<<=3 : assert a==40 : "\ + "a>>=1 : assert a==20 : nop" +#define AUTOTEST_OPERATORASSIGN2 "a=1 : a+=2 : assert a==3 : repeat 2 : a+=10 : rend : assert a==23: a=1 : a-=2 : assert a==-1 : repeat 2 : a-=10 : rend : assert a==-21: " \ + "a=3 : a*=2 : assert a==6 : repeat 2 : a*=10 : rend : assert a==600: a=600 : a/=2 : assert a==300 : repeat 2 : a/=10 : rend : assert a==3 : nop" +#define AUTOTEST_OPERATORASSIGN3 "a=1 : a += 2 : assert a==3 : repeat 2 : a += 10 : rend : assert a==23: a=1 : a -= 2 : assert a==-1 : repeat 2 : a -= 10 : rend : assert a==-21: " \ + "a=3 : a *= 2 : assert a==6 : repeat 2 : a *= 10 : rend : assert a==600: a=600 : a /= 2 : assert a==300 : repeat 2 : a /= 10 : rend : assert a==3 : nop" + +#define AUTOTEST_MODULE01 "org 0: nop: preums nop : .prox1 : djnz preums : djnz .prox1 : defs 200 : djnz gourni_preums: djnz gourni_preums.prox1: djnz grouik_preums: " \ + "djnz grouik_preums.prox1: module grouik: preums nop: .prox1: djnz preums: djnz .prox1: djnz gourni_preums: module gourni: ld (.prox1),a: ld (preums.prox1),a: " \ + "preums nop: .prox1: djnz preums: djnz .prox1: djnz grouik_preums: assert preums!=1: module : plop: : module quatre: : jp plop: bip: jr bip: " \ + " : assert preums==1: module OFF: : assert preums==1 " + +#define AUTOTEST_PUSHPOPGLOBAL "unglobal: nop: repeat 2: @unlocal: .prox nop: rend: .prox nop: apres=$: macro unemacro: @inside: nop: .prox: nop: assert .prox>@inside: djnz .prox: " \ + "mend: macro deuxmacros: @inside: nop: .prox: nop: unemacro: nop: djnz .prox: assert .prox>@inside: mend: unemacro (void): assert .proxtroisglobal: module: jr un_doublon: jr deux_doublon: jr un_deuxglobal.prox: jr deux_troisglobal.prox " + +#define AUTOTEST_MODULE03 "unglobal: nop: .prox: nop: module un: deuxglobal: nop: .prox: nop: djnz .prox: nop: doublon: nop: module deux: troisglobal: nop: " \ + " .prox: nop: djnz .prox: nop: doublon: nop: assert doublon>troisglobal: endmodule: jr un_doublon: jr deux_doublon: jr un_deuxglobal.prox: jr deux_troisglobal.prox " + +#define AUTOTEST_GETNOP_LD "ticker start,testouille:"\ + "ld a,1: ld a,b: ld b,a: ld a,i: ld i,a: ld a,r: ld r,a:"\ + "ld a,(5): ld a,(hl): ld a,(de): ld (de),a: ld (hl),h: ld a,lx: ld lx,c:"\ + "ld (1234),a: ld hl,1234: ld bc,1234: ld ix,1234: ld hl,(123): ld bc,(123): ld ix,(123): ld sp,(123):"\ + "ld (123),hl: ld (123),de: ld (123),iy: ld (123),sp: ld yh,45: ld sp,hl: ld sp,ix:"\ + "ticker stop,testouille:"\ + "v1=getnop('ld a,1: ld a,b: ld b,a: ld a,i: ld i,a: ld a,r: ld r,a'):"\ + "v1+=getnop('ld a,(5): ld a,(hl): ld a,(de): ld (de),a: ld (hl),h: ld a,lx: ld lx,c'):"\ + "v1+=getnop('ld (1234),a: ld hl,1234: ld bc,1234: ld ix,1234: ld hl,(123): ld bc,(123): ld ix,(123): ld sp,(123)'):"\ + "v1+=getnop('ld (123),hl: ld (123),de: ld (123),iy: ld (123),sp: ld yh,45: ld sp,hl: ld sp,ix'):"\ + "assert v1==testouille" + +#define AUTOTEST_DELAYED_EQU "ld (ix + PLY_AKM_Data_OffsetPtStartTrack + 1),h:PLY_AKM_Track1_Data::" \ + "PLY_AKM_Track1_PtStartTrack defw 0:PLY_AKM_Data_OffsetPtStartTrack "\ + " equ PLY_AKM_Track1_PtStartTrack - PLY_AKM_Track1_Data" + +#define AUTOTEST_TICKERNOP_FULL "ticker start,v1 : rla: rlca: rrca: rra: nop: ccf: daa: scf: cpl: exx: ei: di : ticker stop,v1:"\ +"ticker start,v2 :im 0: neg : rst #10: retn : reti:ticker stop,v2:"\ +"ticker start,v3 :cpir : cpdr : cpd : cpi : outi : outd : ldd :ldi :ldir:lddr:inir:indr:otir:otdr:ind:ini:ticker stop,v3:"\ +"ticker start,v4 :rld:rrd:cp (hl):cp #12:cp a:cp c:cp (ix+0):cp (iy+5):cp ly:cp xl:ticker stop,v4:"\ +"assert v1==getnop('rla: rlca: rrca: rra: nop: ccf: daa: scf: cpl: exx: ei: di'):"\ +"assert v2==getnop('im : neg : rst : retn : reti'):"\ +"assert v3==getnop('cpir : cpdr : cpd : cpi : outi : outd : ldd :ldi :ldir:lddr:inir:indr:otir:otdr:ind:ini'):"\ +"assert v4==getnop('rld:rrd:cp (hl):cp #12:cp a:cp c:cp (ix+0):cp (iy+5):cp ly:cp xl'):"\ +"ticker start,v5 : ex af,af' : ex hl,de : ex de,hl : ex (sp),hl : ex hl,(sp) : ex (sp),ix : ex ix,(sp) : exx : ticker stop,v5:"\ +"assert v5==getnop(\"ex af,af' : ex hl,de : ex de,hl : ex (sp),hl : ex hl,(sp) : ex (sp),ix : ex ix,(sp) : exx\"):"\ +"ticker start,v6 : push af : push bc : push ix : pop ix : pop bc : pop af : ticker stop,v6:"\ +"ticker start,v7 : sla a : sla b : sla (hl) : sla (ix+5) : sla (ix-20),b : ticker stop,v7:"\ +"assert v7==getnop('sla a : sla b : sla (hl) : sla (ix+5) : sla (ix-20),b'):"\ +"ticker start,v8 : sll a : sll b : sll (hl) : sll (ix+5) : sll (ix-20),b : ticker stop,v8:"\ +"assert v8==getnop('sll a : sll b : sll (hl) : sll (ix+5) : sll (ix-20),b'):"\ +"ticker start,v9 : sra a : sra b : sra (hl) : sra (ix+5) : sra (ix-20),b : ticker stop,v9:"\ +"assert v9==getnop('sra a : sra b : sra (hl) : sra (ix+5) : sra (ix-20),b'):"\ +"ticker start,v10 : srl a : srl b : srl (hl) : srl (ix+5) : srl (ix-20),b : ticker stop,v10:"\ +"assert v10==getnop('srl a : srl b : srl (hl) : srl (ix+5) : srl (ix-20),b'):"\ +"ticker start,v11 : rl a : rl b : rl (hl) : rl (ix+5) : rl (ix-20),b : ticker stop,v11:"\ +"assert v11==getnop('rl a : rl b : rl (hl) : rl (ix+5) : rl (ix-20),b'):"\ +"ticker start,v12 : rlc a : rlc b : rlc (hl) : rlc (ix+5) : rlc (ix-20),b : ticker stop,v12:"\ +"assert v12==getnop('rlc a : rlc b : rlc (hl) : rlc (ix+5) : rlc (ix-20),b'):"\ +"ticker start,v13 : rr a : rr b : rr (hl) : rr (ix+5) : rr (ix-20),b : ticker stop,v13:"\ +"assert v13==getnop('rr a : rr b : rr (hl) : rr (ix+5) : rr (ix-20),b'):"\ +"ticker start,v14 : rrc a : rrc b : rrc (hl) : rrc (ix+5) : rrc (ix-20),b : ticker stop,v14:"\ +"assert v14==getnop('rrc a : rrc b : rrc (hl) : rrc (ix+5) : rrc (ix-20),b'):"\ +"ticker start,v20 : out (c),a : out (c),c : out (0),a : out (c),0 : in a,(c) : in f,(c) : in a,(0) : ticker stop,v20:"\ +"assert v20==getnop('out (c),a : out (c),c : out (0),a : out (c),0 : in a,(c) : in f,(c) : in a,(0) '):"\ +"ticker start,v21 : add a,a : add b : add ix,bc : add iy,sp : add hl,de : add (hl) : add xl : add (ix+3) : add #12 : ticker stop,v21:"\ +"assert v21==getnop('add a,a : add b : add ix,bc : add iy,sp : add hl,de : add (hl) : add xl : add (ix+3) : add #12'):"\ +"ticker start,v22 : adc hl,bc : adc hl,hl : sbc hl,hl : sbc hl,sp : sbc hl,bc : adc hl,sp : ticker stop,v22:"\ +"assert v22==getnop('adc hl,bc : adc hl,hl : sbc hl,hl : sbc hl,sp : sbc hl,bc : adc hl,sp'):"\ +"ticker start,v23 : sub a : sub a,b : sub c : sub #44 : sub (hl) : sub xl : sub (ix+20) : ticker stop,v23:"\ +"assert v23==getnop('sub a : sub a,b : sub c : sub #44 : sub (hl) : sub xl : sub (ix+20)'):"\ +"ticker start,v24 : xor a : xor b : xor c : xor #44 : xor (hl) : xor xl : xor (ix+20) : ticker stop,v24:"\ +"assert v24==getnop('xor a : xor b : xor c : xor #44 : xor (hl) : xor xl : xor (ix+20)'):"\ +"ticker start,v25 : and a : and b : and c : and #44 : and (hl) : and xl : and (ix+20) : ticker stop,v25:"\ +"assert v25==getnop('and a : and b : and c : and #44 : and (hl) : and xl : and (ix+20)'):"\ +"ticker start,v26 : or a : or b : or c : or #44 : or (hl) : or xl : or (ix+20) : ticker stop,v26:"\ +"assert v26==getnop('or a : or b : or c : or #44 : or (hl) : or xl : or (ix+20)'):"\ +"ticker start,v27 : bit 0,a : bit 1,b : bit 2,c : bit 3,d : bit 4,(hl) : bit 5,(ix+0) : bit 6,(ix+0),e : ticker stop,v27:"\ +"assert v27==getnop('bit 0,a : bit 1,b : bit 2,c : bit 3,d : bit 4,(hl) : bit 5,(ix+0) : bit 6,(ix+0),e'):"\ +"ticker start,v28 : res 0,a : res 1,b : res 2,c : res 3,d : res 4,(hl) : res 5,(ix+0) : res 6,(ix+0),e : ticker stop,v28:"\ +"assert v28==getnop('res 0,a : res 1,b : res 2,c : res 3,d : res 4,(hl) : res 5,(ix+0) : res 6,(ix+0),e'):"\ +"ticker start,v29 : set 0,a : set 1,b : set 2,c : set 3,d : set 4,(hl) : set 5,(ix+0) : set 6,(ix+0),e : ticker stop,v29:"\ +"assert v29==getnop('set 0,a : set 1,b : set 2,c : set 3,d : set 4,(hl) : set 5,(ix+0) : set 6,(ix+0),e'):"\ +"ticker start,v30 : dec a : dec b : dec lx : dec bc : dec hl : dec sp : dec ix : dec (hl) : dec (ix+100) : ticker stop,v30:"\ +"assert v30==getnop('dec a : dec b : dec lx : dec bc : dec hl : dec sp : dec ix : dec (hl) : dec (ix+100) '):"\ +"ticker start,v31 : inc a : inc b : inc lx : inc bc : inc hl : inc sp : inc ix : inc (hl) : inc (ix+100) : ticker stop,v31:"\ +"assert v31==getnop('inc a : inc b : inc lx : inc bc : inc hl : inc sp : inc ix : inc (hl) : inc (ix+100) '):"\ +"ticker start,v32 : jp 0 : jp c,0 : jp pe,0 : jp (ix) : jp (hl) : djnz $ : ticker stop,v32:"\ +"assert v32==getnop('jp 0 : jp c,0 : jp pe,0 : jp (ix) : jp (hl) : djnz $'):"\ +"ticker start,v40 : ld a,i : ld a,r : ld r,a : ld i,a : ld a,a : ld b,c : ld d,e : ld a,yl : ld d,yh : ld a,(bc) : ticker stop,v40:"\ +"assert v40==getnop('ld a,i : ld a,r : ld r,a : ld i,a : ld a,a : ld b,c : ld d,e : ld a,yl : ld d,yh : ld a,(bc)'):"\ +"ticker start,v41 : ld a,(de) : ld a,(hl) : ld l,(hl) : ld (hl),d : ld (hl),a : ld a,#12 : ld b,#12 : ld a,(#1234) : ld (#1234),a : ticker stop,v41:"\ +"assert v41==getnop('ld a,(de) : ld a,(hl) : ld l,(hl) : ld (hl),d : ld (hl),a : ld a,#12 : ld b,#12 : ld a,(#1234) : ld (#1234),a'):"\ +"ticker start,v42 : ld bc,123 : ld hl,123 : ld sp,123 : ld bc,(123) : ld hl,(123) : ld sp,(123) : ld ix,123 : ld ix,(123) : ticker stop,v42:"\ +"assert v42==getnop('ld bc,123 : ld hl,123 : ld sp,123 : ld bc,(123) : ld hl,(123) : ld sp,(123) : ld ix,123 : ld ix,(123)'):"\ +"ticker start,v43 : ld (123),bc : ld (123),hl : ld (123),ix : ld (123),sp : ld hy,#12 : ld ly,b : ld sp,hl : ld sp,ix : ticker stop,v43:"\ +"assert v43==getnop('ld (123),bc : ld (123),hl : ld (123),ix : ld (123),sp : ld hy,#12 : ld ly,b : ld sp,hl : ld sp,ix'):"\ +"ticker start,v44 : ld a,(ix+0) : ld h,(ix+0) : ld (ix+0),a : ld (ix+0),l : ld (ix+0),#12 : ticker stop,v44:"\ +"assert v44==getnop('ld a,(ix+0) : ld h,(ix+0) : ld (ix+0),a : ld (ix+0),l : ld (ix+0),#12')" + +#define AUTOTEST_TICKER_FULL "ticker start,v1 : rla: rlca: rrca: rra: nop: ccf: daa: scf: cpl: exx: ei: di : ticker stopzx,v1:"\ +"ticker start,v2 :im 0: neg : rst #10: retn : reti:ticker stopzx,v2:"\ +"ticker start,v3 :cpir : cpdr : cpd : cpi : outi : outd : ldd :ldi :ldir:lddr:inir:indr:otir:otdr:ind:ini:ticker stopzx,v3:"\ +"ticker start,v4 :rld:rrd::cp (hl):cp #12:cp a:cp c:cp (ix+0):cp (iy+5):cp ly:cp xl:ticker stopzx,v4:"\ +"assert v1==gettick('rla: rlca: rrca: rra: nop: ccf: daa: scf: cpl: exx: ei: di'):"\ +"assert v2==gettick('im : neg : rst : retn : reti'):"\ +"assert v3==gettick('cpir : cpdr : cpd : cpi : outi : outd : ldd :ldi :ldir:lddr:inir:indr:otir:otdr:ind:ini'):"\ +"assert v4==gettick('rld:rrd:cp (hl):cp #12:cp a:cp c:cp (ix+0):cp (iy+5):cp ly:cp xl'):"\ +"ticker start,v5 : ex af,af' : ex hl,de : ex de,hl : ex (sp),hl : ex hl,(sp) : ex (sp),ix : ex ix,(sp) : exx : ticker stopzx,v5:"\ +"assert v5==gettick(\"ex af,af' : ex hl,de : ex de,hl : ex (sp),hl : ex hl,(sp) : ex (sp),ix : ex ix,(sp) : exx\"):"\ +"ticker start,v6 : push af : push bc : push ix : pop ix : pop bc : pop af : ticker stopzx,v6:"\ +"ticker start,v7 : sla a : sla b : sla (hl) : sla (ix+5) : sla (ix-20),b : ticker stopzx,v7:"\ +"assert v7==gettick('sla a : sla b : sla (hl) : sla (ix+5) : sla (ix-20),b'):"\ +"ticker start,v8 : sll a : sll b : sll (hl) : sll (ix+5) : sll (ix-20),b : ticker stopzx,v8:"\ +"assert v8==gettick('sll a : sll b : sll (hl) : sll (ix+5) : sll (ix-20),b'):"\ +"ticker start,v9 : sra a : sra b : sra (hl) : sra (ix+5) : sra (ix-20),b : ticker stopzx,v9:"\ +"assert v9==gettick('sra a : sra b : sra (hl) : sra (ix+5) : sra (ix-20),b'):"\ +"ticker start,v10 : srl a : srl b : srl (hl) : srl (ix+5) : srl (ix-20),b : ticker stopzx,v10:"\ +"assert v10==gettick('srl a : srl b : srl (hl) : srl (ix+5) : srl (ix-20),b'):"\ +"ticker start,v11 : rl a : rl b : rl (hl) : rl (ix+5) : rl (ix-20),b : ticker stopzx,v11:"\ +"assert v11==gettick('rl a : rl b : rl (hl) : rl (ix+5) : rl (ix-20),b'):"\ +"ticker start,v12 : rlc a : rlc b : rlc (hl) : rlc (ix+5) : rlc (ix-20),b : ticker stopzx,v12:"\ +"assert v12==gettick('rlc a : rlc b : rlc (hl) : rlc (ix+5) : rlc (ix-20),b'):"\ +"ticker start,v13 : rr a : rr b : rr (hl) : rr (ix+5) : rr (ix-20),b : ticker stopzx,v13:"\ +"assert v13==gettick('rr a : rr b : rr (hl) : rr (ix+5) : rr (ix-20),b'):"\ +"ticker start,v14 : rrc a : rrc b : rrc (hl) : rrc (ix+5) : rrc (ix-20),b : ticker stopzx,v14:"\ +"assert v14==gettick('rrc a : rrc b : rrc (hl) : rrc (ix+5) : rrc (ix-20),b'):"\ +"ticker start,v20 : out (c),a : out (c),c : out (0),a : out (c),0 : in a,(c) : in f,(c) : in a,(0) : ticker stopzx,v20:"\ +"assert v20==gettick('out (c),a : out (c),c : out (0),a : out (c),0 : in a,(c) : in f,(c) : in a,(0) '):"\ +"ticker start,v21 : add a,a : add b : add ix,bc : add iy,sp : add hl,de : add (hl) : add xl : add (ix+3) : add #12 : ticker stopzx,v21:"\ +"assert v21==gettick('add a,a : add b : add ix,bc : add iy,sp : add hl,de : add (hl) : add xl : add (ix+3) : add #12'):"\ +"ticker start,v22 : adc hl,bc : adc hl,hl : sbc hl,hl : sbc hl,sp : sbc hl,bc : adc hl,sp : ticker stopzx,v22:"\ +"assert v22==gettick('adc hl,bc : adc hl,hl : sbc hl,hl : sbc hl,sp : sbc hl,bc : adc hl,sp'):"\ +"ticker start,v23 : sub a : sub a,b : sub c : sub #44 : sub (hl) : sub xl : sub (ix+20) : ticker stopzx,v23:"\ +"assert v23==gettick('sub a : sub a,b : sub c : sub #44 : sub (hl) : sub xl : sub (ix+20)'):"\ +"ticker start,v24 : xor a : xor b : xor c : xor #44 : xor (hl) : xor xl : xor (ix+20) : ticker stopzx,v24:"\ +"assert v24==gettick('xor a : xor b : xor c : xor #44 : xor (hl) : xor xl : xor (ix+20)'):"\ +"ticker start,v25 : and a : and b : and c : and #44 : and (hl) : and xl : and (ix+20) : ticker stopzx,v25:"\ +"assert v25==gettick('and a : and b : and c : and #44 : and (hl) : and xl : and (ix+20)'):"\ +"ticker start,v26 : or a : or b : or c : or #44 : or (hl) : or xl : or (ix+20) : ticker stopzx,v26:"\ +"assert v26==gettick('or a : or b : or c : or #44 : or (hl) : or xl : or (ix+20)'):"\ +"ticker start,v27 : bit 0,a : bit 1,b : bit 2,c : bit 3,d : bit 4,(hl) : bit 5,(ix+0) : bit 6,(ix+0),e : ticker stopzx,v27:"\ +"assert v27==gettick('bit 0,a : bit 1,b : bit 2,c : bit 3,d : bit 4,(hl) : bit 5,(ix+0) : bit 6,(ix+0),e'):"\ +"ticker start,v28 : res 0,a : res 1,b : res 2,c : res 3,d : res 4,(hl) : res 5,(ix+0) : res 6,(ix+0),e : ticker stopzx,v28:"\ +"assert v28==gettick('res 0,a : res 1,b : res 2,c : res 3,d : res 4,(hl) : res 5,(ix+0) : res 6,(ix+0),e'):"\ +"ticker start,v29 : set 0,a : set 1,b : set 2,c : set 3,d : set 4,(hl) : set 5,(ix+0) : set 6,(ix+0),e : ticker stopzx,v29:"\ +"assert v29==gettick('set 0,a : set 1,b : set 2,c : set 3,d : set 4,(hl) : set 5,(ix+0) : set 6,(ix+0),e'):"\ +"ticker start,v30 : dec a : dec b : dec lx : dec bc : dec hl : dec sp : dec ix : dec (hl) : dec (ix+100) : ticker stopzx,v30:"\ +"assert v30==gettick('dec a : dec b : dec lx : dec bc : dec hl : dec sp : dec ix : dec (hl) : dec (ix+100) '):"\ +"ticker start,v31 : inc a : inc b : inc lx : inc bc : inc hl : inc sp : inc ix : inc (hl) : inc (ix+100) : ticker stopzx,v31:"\ +"assert v31==gettick('inc a : inc b : inc lx : inc bc : inc hl : inc sp : inc ix : inc (hl) : inc (ix+100) '):"\ +"ticker start,v32 : jp 0 : jp c,0 : jp pe,0 : jp (ix) : jp (hl) : djnz $ : ticker stopzx,v32:"\ +"assert v32==gettick('jp 0 : jp c,0 : jp pe,0 : jp (ix) : jp (hl) : djnz $'):"\ +"ticker start,v40 : ld a,i : ld a,r : ld r,a : ld i,a : ld a,a : ld b,c : ld d,e : ld a,yl : ld d,yh : ld a,(bc) : ticker stopzx,v40:"\ +"assert v40==gettick('ld a,i : ld a,r : ld r,a : ld i,a : ld a,a : ld b,c : ld d,e : ld a,yl : ld d,yh : ld a,(bc)'):"\ +"ticker start,v41 : ld a,(de) : ld a,(hl) : ld l,(hl) : ld (hl),d : ld (hl),a : ld a,#12 : ld b,#12 : ld a,(#1234) : ld (#1234),a : ticker stopzx,v41:"\ +"assert v41==gettick('ld a,(de) : ld a,(hl) : ld l,(hl) : ld (hl),d : ld (hl),a : ld a,#12 : ld b,#12 : ld a,(#1234) : ld (#1234),a'):"\ +"ticker start,v42 : ld bc,123 : ld hl,123 : ld sp,123 : ld bc,(123) : ld hl,(123) : ld sp,(123) : ld ix,123 : ld ix,(123) : ticker stopzx,v42:"\ +"assert v42==gettick('ld bc,123 : ld hl,123 : ld sp,123 : ld bc,(123) : ld hl,(123) : ld sp,(123) : ld ix,123 : ld ix,(123)'):"\ +"ticker start,v43 : ld (123),bc : ld (123),hl : ld (123),ix : ld (123),sp : ld hy,#12 : ld ly,b : ld sp,hl : ld sp,ix : ticker stopzx,v43:"\ +"assert v43==gettick('ld (123),bc : ld (123),hl : ld (123),ix : ld (123),sp : ld hy,#12 : ld ly,b : ld sp,hl : ld sp,ix'):"\ +"ticker start,v44 : ld a,(ix+0) : ld h,(ix+0) : ld (ix+0),a : ld (ix+0),l : ld (ix+0),#12 : ticker stopzx,v44:"\ +"assert v44==gettick('ld a,(ix+0) : ld h,(ix+0) : ld (ix+0),a : ld (ix+0),l : ld (ix+0),#12')" + +#define AUTOTEST_GETSIZE "bank:push de:assert $==getsize('push de'):bank:sub #12:assert $==getsize('sub #12'):bank:rst #10:assert $==getsize('rst #10'):" \ +"bank:ret c:assert $==getsize('ret c'):bank:exx:assert $==getsize('exx'):bank:jp c,#1234:assert $==getsize('jp c,#1234')" \ +":bank:in a,(#12):assert $==getsize('in a,(#12)'):bank:call c,#1234:assert $==getsize('call c,#1234'):bank:nop:assert $==getsize('nop')" \ +":bank:sbc #12:assert $==getsize('sbc #12'):bank:rst #18:assert $==getsize('rst #18'):bank:ret po:assert $==getsize('ret po')" \ +":bank:pop hl:assert $==getsize('pop hl'):bank:jp po,#1234:assert $==getsize('jp po,#1234'):bank:ex (sp),hl:assert $==getsize('ex (sp),hl')" \ +":bank:call po,#1234:assert $==getsize('call po,#1234'):bank:push hl:assert $==getsize('push hl'):bank:and #12:assert $==getsize('and #12')" \ +":bank:rst #20:assert $==getsize('rst #20'):bank:ret pe:assert $==getsize('ret pe'):bank:jp (hl):assert $==getsize('jp (hl)')" \ +":bank:jp pe,#1234:assert $==getsize('jp pe,#1234'):bank:ex de,hl:assert $==getsize('ex de,hl'):bank:call pe,#1234:assert $==getsize('call pe,#1234')" \ +":bank:nop:assert $==getsize('nop'):bank:xor #12:assert $==getsize('xor #12'):bank:rst #28:assert $==getsize('rst #28')" \ +":bank:ret p:assert $==getsize('ret p'):bank:pop af:assert $==getsize('pop af'):bank:jp p,#1234:assert $==getsize('jp p,#1234')" \ +":bank:di:assert $==getsize('di'):bank:call p,#1234:assert $==getsize('call p,#1234'):bank:push af:assert $==getsize('push af')" \ +":bank:or #12:assert $==getsize('or #12'):bank:rst #30:assert $==getsize('rst #30'):bank:ret m:assert $==getsize('ret m')" \ +":bank:ld sp,hl:assert $==getsize('ld sp,hl'):bank:jp m,#1234:assert $==getsize('jp m,#1234'):bank:ei:assert $==getsize('ei')" \ +":bank:call m,#1234:assert $==getsize('call m,#1234'):bank:nop:assert $==getsize('nop'):bank:cp #12:assert $==getsize('cp #12')" \ +":bank:rst #38:assert $==getsize('rst #38'):bank:in b,(c):assert $==getsize('in b,(c)'):bank:out (c),b:assert $==getsize('out (c),b')" \ +":bank:sbc hl,bc:assert $==getsize('sbc hl,bc'):bank:ld (#1234),bc:assert $==getsize('ld (#1234),bc'):bank:neg:assert $==getsize('neg')" \ +":bank:retn:assert $==getsize('retn'):bank:im 0:assert $==getsize('im 0'):bank:ld i,a:assert $==getsize('ld i,a')" \ +":bank:in c,(c):assert $==getsize('in c,(c)'):bank:out (c),c:assert $==getsize('out (c),c'):bank:adc hl,bc:assert $==getsize('adc hl,bc')" \ +":bank:ld bc,(#1234):assert $==getsize('ld bc,(#1234)'):bank:reti:assert $==getsize('reti'):bank:ld r,a:assert $==getsize('ld r,a')" \ +":bank:in d,(c):assert $==getsize('in d,(c)'):bank:out (c),d:assert $==getsize('out (c),d'):bank:sbc hl,de:assert $==getsize('sbc hl,de')" \ +":bank:ld (#1234),de:assert $==getsize('ld (#1234),de'):bank:retn:assert $==getsize('retn'):bank:im 1:assert $==getsize('im 1')" \ +":bank:ld a,i:assert $==getsize('ld a,i'):bank:in e,(c):assert $==getsize('in e,(c)'):bank:out (c),e:assert $==getsize('out (c),e')" \ +":bank:adc hl,de:assert $==getsize('adc hl,de'):bank:ld de,(#1234):assert $==getsize('ld de,(#1234)'):bank:im 2:assert $==getsize('im 2')" \ +":bank:ld a,r:assert $==getsize('ld a,r'):bank:in h,(c):assert $==getsize('in h,(c)'):bank:out (c),h:assert $==getsize('out (c),h')" \ +":bank:sbc hl,hl:assert $==getsize('sbc hl,hl'):bank:rrd:assert $==getsize('rrd'):bank:in l,(c):assert $==getsize('in l,(c)')" \ +":bank:out (c),l:assert $==getsize('out (c),l'):bank:adc hl,hl:assert $==getsize('adc hl,hl'):bank:rld:assert $==getsize('rld')" \ +":bank:in 0,(c):assert $==getsize('in 0,(c)'):bank:out (c),0:assert $==getsize('out (c),0'):bank:sbc hl,sp:assert $==getsize('sbc hl,sp')" \ +":bank:ld (#1234),sp:assert $==getsize('ld (#1234),sp'):bank:in a,(c):assert $==getsize('in a,(c)'):bank:out (c),a:assert $==getsize('out (c),a')" \ +":bank:adc hl,sp:assert $==getsize('adc hl,sp'):bank:ld sp,(#1234):assert $==getsize('ld sp,(#1234)'):bank:ldi:assert $==getsize('ldi')" \ +":bank:cpi:assert $==getsize('cpi'):bank:ini:assert $==getsize('ini'):bank:outi:assert $==getsize('outi')" \ +":bank:ldd:assert $==getsize('ldd'):bank:cpd:assert $==getsize('cpd'):bank:ind:assert $==getsize('ind')" \ +":bank:outd:assert $==getsize('outd'):bank:ldir:assert $==getsize('ldir'):bank:cpir:assert $==getsize('cpir')" \ +":bank:inir:assert $==getsize('inir'):bank:otir:assert $==getsize('otir'):bank:lddr:assert $==getsize('lddr')" \ +":bank:cpdr:assert $==getsize('cpdr'):bank:indr:assert $==getsize('indr'):bank:otdr:assert $==getsize('otdr')" \ +":bank:rlc b:assert $==getsize('rlc b'):bank:rlc c:assert $==getsize('rlc c'):bank:rlc d:assert $==getsize('rlc d')" \ +":bank:rlc e:assert $==getsize('rlc e'):bank:rlc h:assert $==getsize('rlc h'):bank:rlc l:assert $==getsize('rlc l')" \ +":bank:rlc (hl):assert $==getsize('rlc (hl)'):bank:rlc a:assert $==getsize('rlc a'):bank:rrc b:assert $==getsize('rrc b')" \ +":bank:rrc c:assert $==getsize('rrc c'):bank:rrc d:assert $==getsize('rrc d'):bank:rrc e:assert $==getsize('rrc e')" \ +":bank:rrc h:assert $==getsize('rrc h'):bank:rrc l:assert $==getsize('rrc l'):bank:rrc (hl):assert $==getsize('rrc (hl)')" \ +":bank:rrc a:assert $==getsize('rrc a'):bank:rl b:assert $==getsize('rl b'):bank:rl c:assert $==getsize('rl c')" \ +":bank:rl d:assert $==getsize('rl d'):bank:rl e:assert $==getsize('rl e'):bank:rl h:assert $==getsize('rl h')" \ +":bank:rl l:assert $==getsize('rl l'):bank:rl (hl):assert $==getsize('rl (hl)'):bank:rl a:assert $==getsize('rl a')" \ +":bank:rr b:assert $==getsize('rr b'):bank:rr c:assert $==getsize('rr c'):bank:rr d:assert $==getsize('rr d')" \ +":bank:rr e:assert $==getsize('rr e'):bank:rr h:assert $==getsize('rr h'):bank:rr l:assert $==getsize('rr l')" \ +":bank:rr (hl):assert $==getsize('rr (hl)'):bank:rr a:assert $==getsize('rr a'):bank:sla b:assert $==getsize('sla b')" \ +":bank:sla c:assert $==getsize('sla c'):bank:sla d:assert $==getsize('sla d'):bank:sla e:assert $==getsize('sla e')" \ +":bank:sla h:assert $==getsize('sla h'):bank:sla l:assert $==getsize('sla l'):bank:sla (hl):assert $==getsize('sla (hl)')" \ +":bank:sla a:assert $==getsize('sla a'):bank:sra b:assert $==getsize('sra b'):bank:sra c:assert $==getsize('sra c')" \ +":bank:sra d:assert $==getsize('sra d'):bank:sra e:assert $==getsize('sra e'):bank:sra h:assert $==getsize('sra h')" \ +":bank:sra l:assert $==getsize('sra l'):bank:sra (hl):assert $==getsize('sra (hl)'):bank:sra a:assert $==getsize('sra a')" \ +":bank:sll b:assert $==getsize('sll b'):bank:sll c:assert $==getsize('sll c'):bank:sll d:assert $==getsize('sll d')" \ +":bank:sll e:assert $==getsize('sll e'):bank:sll h:assert $==getsize('sll h'):bank:sll l:assert $==getsize('sll l')" \ +":bank:sll (hl):assert $==getsize('sll (hl)'):bank:sll a:assert $==getsize('sll a'):bank:srl b:assert $==getsize('srl b')" \ +":bank:srl c:assert $==getsize('srl c'):bank:srl d:assert $==getsize('srl d'):bank:srl e:assert $==getsize('srl e')" \ +":bank:srl h:assert $==getsize('srl h'):bank:srl l:assert $==getsize('srl l'):bank:srl (hl):assert $==getsize('srl (hl)')" \ +":bank:srl a:assert $==getsize('srl a'):bank:bit 0,b:assert $==getsize('bit 0,b'):bank:bit 0,c:assert $==getsize('bit 0,c')" \ +":bank:bit 0,d:assert $==getsize('bit 0,d'):bank:bit 0,e:assert $==getsize('bit 0,e'):bank:bit 0,h:assert $==getsize('bit 0,h')" \ +":bank:bit 0,l:assert $==getsize('bit 0,l'):bank:bit 0,(hl):assert $==getsize('bit 0,(hl)'):bank:bit 0,a:assert $==getsize('bit 0,a')" \ +":bank:bit 1,b:assert $==getsize('bit 1,b'):bank:bit 1,c:assert $==getsize('bit 1,c'):bank:bit 1,d:assert $==getsize('bit 1,d')" \ +":bank:bit 1,e:assert $==getsize('bit 1,e'):bank:bit 1,h:assert $==getsize('bit 1,h'):bank:bit 1,l:assert $==getsize('bit 1,l')" \ +":bank:bit 1,(hl):assert $==getsize('bit 1,(hl)'):bank:bit 1,a:assert $==getsize('bit 1,a'):bank:bit 2,b:assert $==getsize('bit 2,b')" \ +":bank:bit 2,c:assert $==getsize('bit 2,c'):bank:bit 2,d:assert $==getsize('bit 2,d'):bank:bit 2,e:assert $==getsize('bit 2,e')" \ +":bank:bit 2,h:assert $==getsize('bit 2,h'):bank:bit 2,l:assert $==getsize('bit 2,l'):bank:bit 2,(hl):assert $==getsize('bit 2,(hl)')" \ +":bank:bit 2,a:assert $==getsize('bit 2,a'):bank:bit 3,b:assert $==getsize('bit 3,b'):bank:bit 3,c:assert $==getsize('bit 3,c')" \ +":bank:bit 3,d:assert $==getsize('bit 3,d'):bank:bit 3,e:assert $==getsize('bit 3,e'):bank:bit 3,h:assert $==getsize('bit 3,h')" \ +":bank:bit 3,l:assert $==getsize('bit 3,l'):bank:bit 3,(hl):assert $==getsize('bit 3,(hl)'):bank:bit 3,a:assert $==getsize('bit 3,a')" \ +":bank:bit 4,b:assert $==getsize('bit 4,b'):bank:bit 4,c:assert $==getsize('bit 4,c'):bank:bit 4,d:assert $==getsize('bit 4,d')" \ +":bank:bit 4,e:assert $==getsize('bit 4,e'):bank:bit 4,h:assert $==getsize('bit 4,h'):bank:bit 4,l:assert $==getsize('bit 4,l')" \ +":bank:bit 4,(hl):assert $==getsize('bit 4,(hl)'):bank:bit 4,a:assert $==getsize('bit 4,a'):bank:bit 5,b:assert $==getsize('bit 5,b')" \ +":bank:bit 5,c:assert $==getsize('bit 5,c'):bank:bit 5,d:assert $==getsize('bit 5,d'):bank:bit 5,e:assert $==getsize('bit 5,e')" \ +":bank:bit 5,h:assert $==getsize('bit 5,h'):bank:bit 5,l:assert $==getsize('bit 5,l'):bank:bit 5,(hl):assert $==getsize('bit 5,(hl)')" \ +":bank:bit 5,a:assert $==getsize('bit 5,a'):bank:bit 6,b:assert $==getsize('bit 6,b'):bank:bit 6,c:assert $==getsize('bit 6,c')" \ +":bank:bit 6,d:assert $==getsize('bit 6,d'):bank:bit 6,e:assert $==getsize('bit 6,e'):bank:bit 6,h:assert $==getsize('bit 6,h')" \ +":bank:bit 6,l:assert $==getsize('bit 6,l'):bank:bit 6,(hl):assert $==getsize('bit 6,(hl)'):bank:bit 6,a:assert $==getsize('bit 6,a')" \ +":bank:bit 7,b:assert $==getsize('bit 7,b'):bank:bit 7,c:assert $==getsize('bit 7,c'):bank:bit 7,d:assert $==getsize('bit 7,d')" \ +":bank:bit 7,e:assert $==getsize('bit 7,e'):bank:bit 7,h:assert $==getsize('bit 7,h'):bank:bit 7,l:assert $==getsize('bit 7,l')" \ +":bank:bit 7,(hl):assert $==getsize('bit 7,(hl)'):bank:bit 7,a:assert $==getsize('bit 7,a'):bank:res 0,b:assert $==getsize('res 0,b')" \ +":bank:res 0,c:assert $==getsize('res 0,c'):bank:res 0,d:assert $==getsize('res 0,d'):bank:res 0,e:assert $==getsize('res 0,e')" \ +":bank:res 0,h:assert $==getsize('res 0,h'):bank:res 0,l:assert $==getsize('res 0,l'):bank:res 0,(hl):assert $==getsize('res 0,(hl)')" \ +":bank:res 0,a:assert $==getsize('res 0,a'):bank:res 1,b:assert $==getsize('res 1,b'):bank:res 1,c:assert $==getsize('res 1,c')" \ +":bank:res 1,d:assert $==getsize('res 1,d'):bank:res 1,e:assert $==getsize('res 1,e'):bank:res 1,h:assert $==getsize('res 1,h')" \ +":bank:res 1,l:assert $==getsize('res 1,l'):bank:res 1,(hl):assert $==getsize('res 1,(hl)'):bank:res 1,a:assert $==getsize('res 1,a')" \ +":bank:res 2,b:assert $==getsize('res 2,b'):bank:res 2,c:assert $==getsize('res 2,c'):bank:res 2,d:assert $==getsize('res 2,d')" \ +":bank:res 2,e:assert $==getsize('res 2,e'):bank:res 2,h:assert $==getsize('res 2,h'):bank:res 2,l:assert $==getsize('res 2,l')" \ +":bank:res 2,(hl):assert $==getsize('res 2,(hl)'):bank:res 2,a:assert $==getsize('res 2,a'):bank:res 3,b:assert $==getsize('res 3,b')" \ +":bank:res 3,c:assert $==getsize('res 3,c'):bank:res 3,d:assert $==getsize('res 3,d'):bank:res 3,e:assert $==getsize('res 3,e')" \ +":bank:res 3,h:assert $==getsize('res 3,h'):bank:res 3,l:assert $==getsize('res 3,l'):bank:res 3,(hl):assert $==getsize('res 3,(hl)')" \ +":bank:res 3,a:assert $==getsize('res 3,a'):bank:res 4,b:assert $==getsize('res 4,b'):bank:res 4,c:assert $==getsize('res 4,c')" \ +":bank:res 4,d:assert $==getsize('res 4,d'):bank:res 4,e:assert $==getsize('res 4,e'):bank:res 4,h:assert $==getsize('res 4,h')" \ +":bank:res 4,l:assert $==getsize('res 4,l'):bank:res 4,(hl):assert $==getsize('res 4,(hl)'):bank:res 4,a:assert $==getsize('res 4,a')" \ +":bank:res 5,b:assert $==getsize('res 5,b'):bank:res 5,c:assert $==getsize('res 5,c'):bank:res 5,d:assert $==getsize('res 5,d')" \ +":bank:res 5,e:assert $==getsize('res 5,e'):bank:res 5,h:assert $==getsize('res 5,h'):bank:res 5,l:assert $==getsize('res 5,l')" \ +":bank:res 5,(hl):assert $==getsize('res 5,(hl)'):bank:res 5,a:assert $==getsize('res 5,a'):bank:res 6,b:assert $==getsize('res 6,b')" \ +":bank:res 6,c:assert $==getsize('res 6,c'):bank:res 6,d:assert $==getsize('res 6,d'):bank:res 6,e:assert $==getsize('res 6,e')" \ +":bank:res 6,h:assert $==getsize('res 6,h'):bank:res 6,l:assert $==getsize('res 6,l'):bank:res 6,(hl):assert $==getsize('res 6,(hl)')" \ +":bank:res 6,a:assert $==getsize('res 6,a'):bank:res 7,b:assert $==getsize('res 7,b'):bank:res 7,c:assert $==getsize('res 7,c')" \ +":bank:res 7,d:assert $==getsize('res 7,d'):bank:res 7,e:assert $==getsize('res 7,e'):bank:res 7,h:assert $==getsize('res 7,h')" \ +":bank:res 7,l:assert $==getsize('res 7,l'):bank:res 7,(hl):assert $==getsize('res 7,(hl)'):bank:res 7,a:assert $==getsize('res 7,a')" \ +":bank:set 0,b:assert $==getsize('set 0,b'):bank:set 0,c:assert $==getsize('set 0,c'):bank:set 0,d:assert $==getsize('set 0,d')" \ +":bank:set 0,e:assert $==getsize('set 0,e'):bank:set 0,h:assert $==getsize('set 0,h'):bank:set 0,l:assert $==getsize('set 0,l')" \ +":bank:set 0,(hl):assert $==getsize('set 0,(hl)'):bank:set 0,a:assert $==getsize('set 0,a'):bank:set 1,b:assert $==getsize('set 1,b')" \ +":bank:set 1,c:assert $==getsize('set 1,c'):bank:set 1,d:assert $==getsize('set 1,d'):bank:set 1,e:assert $==getsize('set 1,e')" \ +":bank:set 1,h:assert $==getsize('set 1,h'):bank:set 1,l:assert $==getsize('set 1,l'):bank:set 1,(hl):assert $==getsize('set 1,(hl)')" \ +":bank:set 1,a:assert $==getsize('set 1,a'):bank:set 2,b:assert $==getsize('set 2,b'):bank:set 2,c:assert $==getsize('set 2,c')" \ +":bank:set 2,d:assert $==getsize('set 2,d'):bank:set 2,e:assert $==getsize('set 2,e'):bank:set 2,h:assert $==getsize('set 2,h')" \ +":bank:set 2,l:assert $==getsize('set 2,l'):bank:set 2,(hl):assert $==getsize('set 2,(hl)'):bank:set 2,a:assert $==getsize('set 2,a')" \ +":bank:set 3,b:assert $==getsize('set 3,b'):bank:set 3,c:assert $==getsize('set 3,c'):bank:set 3,d:assert $==getsize('set 3,d')" \ +":bank:set 3,e:assert $==getsize('set 3,e'):bank:set 3,h:assert $==getsize('set 3,h'):bank:set 3,l:assert $==getsize('set 3,l')" \ +":bank:set 3,(hl):assert $==getsize('set 3,(hl)'):bank:set 3,a:assert $==getsize('set 3,a'):bank:set 4,b:assert $==getsize('set 4,b')" \ +":bank:set 4,c:assert $==getsize('set 4,c'):bank:set 4,d:assert $==getsize('set 4,d'):bank:set 4,e:assert $==getsize('set 4,e')" \ +":bank:set 4,h:assert $==getsize('set 4,h'):bank:set 4,l:assert $==getsize('set 4,l'):bank:set 4,(hl):assert $==getsize('set 4,(hl)')" \ +":bank:set 4,a:assert $==getsize('set 4,a'):bank:set 5,b:assert $==getsize('set 5,b'):bank:set 5,c:assert $==getsize('set 5,c')" \ +":bank:set 5,d:assert $==getsize('set 5,d'):bank:set 5,e:assert $==getsize('set 5,e'):bank:set 5,h:assert $==getsize('set 5,h')" \ +":bank:set 5,l:assert $==getsize('set 5,l'):bank:set 5,(hl):assert $==getsize('set 5,(hl)'):bank:set 5,a:assert $==getsize('set 5,a')" \ +":bank:set 6,b:assert $==getsize('set 6,b'):bank:set 6,c:assert $==getsize('set 6,c'):bank:set 6,d:assert $==getsize('set 6,d')" \ +":bank:set 6,e:assert $==getsize('set 6,e'):bank:set 6,h:assert $==getsize('set 6,h'):bank:set 6,l:assert $==getsize('set 6,l')" \ +":bank:set 6,(hl):assert $==getsize('set 6,(hl)'):bank:set 6,a:assert $==getsize('set 6,a'):bank:set 7,b:assert $==getsize('set 7,b')" \ +":bank:set 7,c:assert $==getsize('set 7,c'):bank:set 7,d:assert $==getsize('set 7,d'):bank:set 7,e:assert $==getsize('set 7,e')" \ +":bank:set 7,h:assert $==getsize('set 7,h'):bank:set 7,l:assert $==getsize('set 7,l'):bank:set 7,(hl):assert $==getsize('set 7,(hl)')" \ +":bank:set 7,a:assert $==getsize('set 7,a'):bank:add ix,bc:assert $==getsize('add ix,bc'):bank:add ix,de:assert $==getsize('add ix,de')" \ +":bank:ld ix,#1234:assert $==getsize('ld ix,#1234'):bank:ld (#1234),ix:assert $==getsize('ld (#1234),ix'):bank:inc ix:assert $==getsize('inc ix')" \ +":bank:inc xh:assert $==getsize('inc xh'):bank:dec xh:assert $==getsize('dec xh'):bank:ld xh,#12:assert $==getsize('ld xh,#12')" \ +":bank:add ix,ix:assert $==getsize('add ix,ix'):bank:ld ix,(#1234):assert $==getsize('ld ix,(#1234)'):bank:dec ix:assert $==getsize('dec ix')" \ +":bank:inc xl:assert $==getsize('inc xl'):bank:dec xl:assert $==getsize('dec xl'):bank:ld xl,#12:assert $==getsize('ld xl,#12')" \ +":bank:inc (ix+#12):assert $==getsize('inc (ix+#12)'):bank:dec (ix+#12):assert $==getsize('dec (ix+#12)'):bank:ld (ix+#12),#34:assert $==getsize('ld (ix+#12),#34')" \ +":bank:add ix,sp:assert $==getsize('add ix,sp'):bank:ld b,xh:assert $==getsize('ld b,xh'):bank:ld b,xl:assert $==getsize('ld b,xl')" \ +":bank:ld b,(ix+#12):assert $==getsize('ld b,(ix+#12)'):bank:ld c,xh:assert $==getsize('ld c,xh'):bank:ld c,xl:assert $==getsize('ld c,xl')" \ +":bank:ld c,(ix+#12):assert $==getsize('ld c,(ix+#12)'):bank:ld d,xh:assert $==getsize('ld d,xh'):bank:ld d,xl:assert $==getsize('ld d,xl')" \ +":bank:ld d,(ix+#12):assert $==getsize('ld d,(ix+#12)'):bank:ld e,xh:assert $==getsize('ld e,xh'):bank:ld e,xl:assert $==getsize('ld e,xl')" \ +":bank:ld e,(ix+#12):assert $==getsize('ld e,(ix+#12)'):bank:ld xh,b:assert $==getsize('ld xh,b'):bank:ld xh,c:assert $==getsize('ld xh,c')" \ +":bank:ld xh,d:assert $==getsize('ld xh,d'):bank:ld xh,e:assert $==getsize('ld xh,e'):bank:ld xh,xh:assert $==getsize('ld xh,xh')" \ +":bank:ld xh,xl:assert $==getsize('ld xh,xl'):bank:ld h,(ix+#12):assert $==getsize('ld h,(ix+#12)'):bank:ld xh,a:assert $==getsize('ld xh,a')" \ +":bank:ld xl,b:assert $==getsize('ld xl,b'):bank:ld xl,c:assert $==getsize('ld xl,c'):bank:ld xl,d:assert $==getsize('ld xl,d')" \ +":bank:ld xl,e:assert $==getsize('ld xl,e'):bank:ld xl,xh:assert $==getsize('ld xl,xh'):bank:ld xl,xl:assert $==getsize('ld xl,xl')" \ +":bank:ld l,(ix+#12):assert $==getsize('ld l,(ix+#12)'):bank:ld xl,a:assert $==getsize('ld xl,a'):bank:ld (ix+#12),b:assert $==getsize('ld (ix+#12),b')" \ +":bank:ld (ix+#12),c:assert $==getsize('ld (ix+#12),c'):bank:ld (ix+#12),d:assert $==getsize('ld (ix+#12),d'):bank:ld (ix+#12),e:assert $==getsize('ld (ix+#12),e')" \ +":bank:ld (ix+#12),h:assert $==getsize('ld (ix+#12),h'):bank:ld (ix+#12),l:assert $==getsize('ld (ix+#12),l'):bank:ld (ix+#12),a:assert $==getsize('ld (ix+#12),a')" \ +":bank:ld a,xh:assert $==getsize('ld a,xh'):bank:ld a,xl:assert $==getsize('ld a,xl'):bank:ld a,(ix+#12):assert $==getsize('ld a,(ix+#12)')" \ +":bank:add xh:assert $==getsize('add xh'):bank:add xl:assert $==getsize('add xl'):bank:add (ix+#12):assert $==getsize('add (ix+#12)')" \ +":bank:adc xh:assert $==getsize('adc xh'):bank:adc xl:assert $==getsize('adc xl'):bank:adc (ix+#12):assert $==getsize('adc (ix+#12)')" \ +":bank:sub xh:assert $==getsize('sub xh'):bank:sub xl:assert $==getsize('sub xl'):bank:sub (ix+#12):assert $==getsize('sub (ix+#12)')" \ +":bank:sbc xh:assert $==getsize('sbc xh'):bank:sbc xl:assert $==getsize('sbc xl'):bank:sbc (ix+#12):assert $==getsize('sbc (ix+#12)')" \ +":bank:and xh:assert $==getsize('and xh'):bank:and xl:assert $==getsize('and xl'):bank:and (ix+#12):assert $==getsize('and (ix+#12)')" \ +":bank:xor xh:assert $==getsize('xor xh'):bank:xor xl:assert $==getsize('xor xl'):bank:xor (ix+#12):assert $==getsize('xor (ix+#12)')" \ +":bank:or xh:assert $==getsize('or xh'):bank:or xl:assert $==getsize('or xl'):bank:or (ix+#12):assert $==getsize('or (ix+#12)')" \ +":bank:cp xh:assert $==getsize('cp xh'):bank:cp xl:assert $==getsize('cp xl'):bank:cp (ix+#12):assert $==getsize('cp (ix+#12)')" \ +":bank:pop ix:assert $==getsize('pop ix'):bank:ex (sp),ix:assert $==getsize('ex (sp),ix'):bank:push ix:assert $==getsize('push ix')" \ +":bank:jp (ix):assert $==getsize('jp (ix)'):bank:ld sp,ix:assert $==getsize('ld sp,ix'):bank:rlc (ix+#12),b:assert $==getsize('rlc (ix+#12),b')" \ +":bank:rlc (ix+#12),c:assert $==getsize('rlc (ix+#12),c'):bank:rlc (ix+#12),d:assert $==getsize('rlc (ix+#12),d'):bank:rlc (ix+#12),e:assert $==getsize('rlc (ix+#12),e')" \ +":bank:rlc (ix+#12),h:assert $==getsize('rlc (ix+#12),h'):bank:rlc (ix+#12),l:assert $==getsize('rlc (ix+#12),l'):bank:rlc (ix+#12):assert $==getsize('rlc (ix+#12)')" \ +":bank:rlc (ix+#12),a:assert $==getsize('rlc (ix+#12),a'):bank:rrc (ix+#12),b:assert $==getsize('rrc (ix+#12),b'):bank:rrc (ix+#12),c:assert $==getsize('rrc (ix+#12),c')" \ +":bank:rrc (ix+#12),d:assert $==getsize('rrc (ix+#12),d'):bank:rrc (ix+#12),e:assert $==getsize('rrc (ix+#12),e'):bank:rrc (ix+#12),h:assert $==getsize('rrc (ix+#12),h')" \ +":bank:rrc (ix+#12),l:assert $==getsize('rrc (ix+#12),l'):bank:rrc (ix+#12):assert $==getsize('rrc (ix+#12)'):bank:rrc (ix+#12),a:assert $==getsize('rrc (ix+#12),a')" \ +":bank:rl (ix+#12),b:assert $==getsize('rl (ix+#12),b'):bank:rl (ix+#12),c:assert $==getsize('rl (ix+#12),c'):bank:rl (ix+#12),d:assert $==getsize('rl (ix+#12),d')" \ +":bank:rl (ix+#12),e:assert $==getsize('rl (ix+#12),e'):bank:rl (ix+#12),h:assert $==getsize('rl (ix+#12),h'):bank:rl (ix+#12),l:assert $==getsize('rl (ix+#12),l')" \ +":bank:rl (ix+#12):assert $==getsize('rl (ix+#12)'):bank:rl (ix+#12),a:assert $==getsize('rl (ix+#12),a'):bank:rr (ix+#12),b:assert $==getsize('rr (ix+#12),b')" \ +":bank:rr (ix+#12),c:assert $==getsize('rr (ix+#12),c'):bank:rr (ix+#12),d:assert $==getsize('rr (ix+#12),d'):bank:rr (ix+#12),e:assert $==getsize('rr (ix+#12),e')" \ +":bank:rr (ix+#12),h:assert $==getsize('rr (ix+#12),h'):bank:rr (ix+#12),l:assert $==getsize('rr (ix+#12),l'):bank:rr (ix+#12):assert $==getsize('rr (ix+#12)')" \ +":bank:rr (ix+#12),a:assert $==getsize('rr (ix+#12),a'):bank:sla (ix+#12),b:assert $==getsize('sla (ix+#12),b'):bank:sla (ix+#12),c:assert $==getsize('sla (ix+#12),c')" \ +":bank:sla (ix+#12),d:assert $==getsize('sla (ix+#12),d'):bank:sla (ix+#12),e:assert $==getsize('sla (ix+#12),e'):bank:sla (ix+#12),h:assert $==getsize('sla (ix+#12),h')" \ +":bank:sla (ix+#12),l:assert $==getsize('sla (ix+#12),l'):bank:sla (ix+#12):assert $==getsize('sla (ix+#12)'):bank:sla (ix+#12),a:assert $==getsize('sla (ix+#12),a')" \ +":bank:sra (ix+#12),b:assert $==getsize('sra (ix+#12),b'):bank:sra (ix+#12),c:assert $==getsize('sra (ix+#12),c'):bank:sra (ix+#12),d:assert $==getsize('sra (ix+#12),d')" \ +":bank:sra (ix+#12),e:assert $==getsize('sra (ix+#12),e'):bank:sra (ix+#12),h:assert $==getsize('sra (ix+#12),h'):bank:sra (ix+#12),l:assert $==getsize('sra (ix+#12),l')" \ +":bank:sra (ix+#12):assert $==getsize('sra (ix+#12)'):bank:sra (ix+#12),a:assert $==getsize('sra (ix+#12),a'):bank:sll (ix+#12),b:assert $==getsize('sll (ix+#12),b')" \ +":bank:sll (ix+#12),c:assert $==getsize('sll (ix+#12),c'):bank:sll (ix+#12),d:assert $==getsize('sll (ix+#12),d'):bank:sll (ix+#12),e:assert $==getsize('sll (ix+#12),e')" \ +":bank:sll (ix+#12),h:assert $==getsize('sll (ix+#12),h'):bank:sll (ix+#12),l:assert $==getsize('sll (ix+#12),l'):bank:sll (ix+#12):assert $==getsize('sll (ix+#12)')" \ +":bank:sll (ix+#12),a:assert $==getsize('sll (ix+#12),a'):bank:srl (ix+#12),b:assert $==getsize('srl (ix+#12),b'):bank:srl (ix+#12),c:assert $==getsize('srl (ix+#12),c')" \ +":bank:srl (ix+#12),d:assert $==getsize('srl (ix+#12),d'):bank:srl (ix+#12),e:assert $==getsize('srl (ix+#12),e'):bank:srl (ix+#12),h:assert $==getsize('srl (ix+#12),h')" \ +":bank:srl (ix+#12),l:assert $==getsize('srl (ix+#12),l'):bank:srl (ix+#12):assert $==getsize('srl (ix+#12)'):bank:srl (ix+#12),a:assert $==getsize('srl (ix+#12),a')" \ +":bank:bit 0,(ix+#12):assert $==getsize('bit 0,(ix+#12)'):bank:bit 1,(ix+#12):assert $==getsize('bit 1,(ix+#12)'):bank:bit 2,(ix+#12):assert $==getsize('bit 2,(ix+#12)')" \ +":bank:bit 3,(ix+#12):assert $==getsize('bit 3,(ix+#12)'):bank:bit 4,(ix+#12):assert $==getsize('bit 4,(ix+#12)'):bank:bit 5,(ix+#12):assert $==getsize('bit 5,(ix+#12)')" \ +":bank:bit 6,(ix+#12):assert $==getsize('bit 6,(ix+#12)'):bank:bit 7,(ix+#12):assert $==getsize('bit 7,(ix+#12)'):bank:bit 0,(ix+#12),d:assert $==getsize('bit 0,(ix+#12),d')" \ +":bank:bit 1,(ix+#12),b:assert $==getsize('bit 1,(ix+#12),b'):bank:bit 2,(ix+#12),c:assert $==getsize('bit 2,(ix+#12),c'):bank:bit 3,(ix+#12),d:assert $==getsize('bit 3,(ix+#12),d')" \ +":bank:bit 4,(ix+#12),e:assert $==getsize('bit 4,(ix+#12),e'):bank:bit 5,(ix+#12),h:assert $==getsize('bit 5,(ix+#12),h'):bank:bit 6,(ix+#12),l:assert $==getsize('bit 6,(ix+#12),l')" \ +":bank:bit 7,(ix+#12),a:assert $==getsize('bit 7,(ix+#12),a'):bank:res 0,(ix+#12),b:assert $==getsize('res 0,(ix+#12),b'):bank:res 0,(ix+#12),c:assert $==getsize('res 0,(ix+#12),c')" \ +":bank:res 0,(ix+#12),d:assert $==getsize('res 0,(ix+#12),d'):bank:res 0,(ix+#12),e:assert $==getsize('res 0,(ix+#12),e'):bank:res 0,(ix+#12),h:assert $==getsize('res 0,(ix+#12),h')" \ +":bank:res 0,(ix+#12),l:assert $==getsize('res 0,(ix+#12),l'):bank:res 0,(ix+#12):assert $==getsize('res 0,(ix+#12)'):bank:res 0,(ix+#12),a:assert $==getsize('res 0,(ix+#12),a')" \ +":bank:res 1,(ix+#12),b:assert $==getsize('res 1,(ix+#12),b'):bank:res 1,(ix+#12),c:assert $==getsize('res 1,(ix+#12),c'):bank:res 1,(ix+#12),d:assert $==getsize('res 1,(ix+#12),d')" \ +":bank:res 1,(ix+#12),e:assert $==getsize('res 1,(ix+#12),e'):bank:res 1,(ix+#12),h:assert $==getsize('res 1,(ix+#12),h'):bank:res 1,(ix+#12),l:assert $==getsize('res 1,(ix+#12),l')" \ +":bank:res 1,(ix+#12):assert $==getsize('res 1,(ix+#12)'):bank:res 1,(ix+#12),a:assert $==getsize('res 1,(ix+#12),a'):bank:res 2,(ix+#12),b:assert $==getsize('res 2,(ix+#12),b')" \ +":bank:res 2,(ix+#12),c:assert $==getsize('res 2,(ix+#12),c'):bank:res 2,(ix+#12),d:assert $==getsize('res 2,(ix+#12),d'):bank:res 2,(ix+#12),e:assert $==getsize('res 2,(ix+#12),e')" \ +":bank:res 2,(ix+#12),h:assert $==getsize('res 2,(ix+#12),h'):bank:res 2,(ix+#12),l:assert $==getsize('res 2,(ix+#12),l'):bank:res 2,(ix+#12):assert $==getsize('res 2,(ix+#12)')" \ +":bank:res 2,(ix+#12),a:assert $==getsize('res 2,(ix+#12),a'):bank:res 3,(ix+#12),b:assert $==getsize('res 3,(ix+#12),b'):bank:res 3,(ix+#12),c:assert $==getsize('res 3,(ix+#12),c')" \ +":bank:res 3,(ix+#12),d:assert $==getsize('res 3,(ix+#12),d'):bank:res 3,(ix+#12),e:assert $==getsize('res 3,(ix+#12),e'):bank:res 3,(ix+#12),h:assert $==getsize('res 3,(ix+#12),h')" \ +":bank:res 3,(ix+#12),l:assert $==getsize('res 3,(ix+#12),l'):bank:res 3,(ix+#12):assert $==getsize('res 3,(ix+#12)'):bank:res 3,(ix+#12),a:assert $==getsize('res 3,(ix+#12),a')" \ +":bank:res 4,(ix+#12),b:assert $==getsize('res 4,(ix+#12),b'):bank:res 4,(ix+#12),c:assert $==getsize('res 4,(ix+#12),c'):bank:res 4,(ix+#12),d:assert $==getsize('res 4,(ix+#12),d')" \ +":bank:res 4,(ix+#12),e:assert $==getsize('res 4,(ix+#12),e'):bank:res 4,(ix+#12),h:assert $==getsize('res 4,(ix+#12),h'):bank:res 4,(ix+#12),l:assert $==getsize('res 4,(ix+#12),l')" \ +":bank:res 4,(ix+#12):assert $==getsize('res 4,(ix+#12)'):bank:res 4,(ix+#12),a:assert $==getsize('res 4,(ix+#12),a'):bank:res 5,(ix+#12),b:assert $==getsize('res 5,(ix+#12),b')" \ +":bank:res 5,(ix+#12),c:assert $==getsize('res 5,(ix+#12),c'):bank:res 5,(ix+#12),d:assert $==getsize('res 5,(ix+#12),d'):bank:res 5,(ix+#12),e:assert $==getsize('res 5,(ix+#12),e')" \ +":bank:res 5,(ix+#12),h:assert $==getsize('res 5,(ix+#12),h'):bank:res 5,(ix+#12),l:assert $==getsize('res 5,(ix+#12),l'):bank:res 5,(ix+#12):assert $==getsize('res 5,(ix+#12)')" \ +":bank:res 5,(ix+#12),a:assert $==getsize('res 5,(ix+#12),a'):bank:res 6,(ix+#12),b:assert $==getsize('res 6,(ix+#12),b'):bank:res 6,(ix+#12),c:assert $==getsize('res 6,(ix+#12),c')" \ +":bank:res 6,(ix+#12),d:assert $==getsize('res 6,(ix+#12),d'):bank:res 6,(ix+#12),e:assert $==getsize('res 6,(ix+#12),e'):bank:res 6,(ix+#12),h:assert $==getsize('res 6,(ix+#12),h')" \ +":bank:res 6,(ix+#12),l:assert $==getsize('res 6,(ix+#12),l'):bank:res 6,(ix+#12):assert $==getsize('res 6,(ix+#12)'):bank:res 6,(ix+#12),a:assert $==getsize('res 6,(ix+#12),a')" \ +":bank:res 7,(ix+#12),b:assert $==getsize('res 7,(ix+#12),b'):bank:res 7,(ix+#12),c:assert $==getsize('res 7,(ix+#12),c'):bank:res 7,(ix+#12),d:assert $==getsize('res 7,(ix+#12),d')" \ +":bank:res 7,(ix+#12),e:assert $==getsize('res 7,(ix+#12),e'):bank:res 7,(ix+#12),h:assert $==getsize('res 7,(ix+#12),h'):bank:res 7,(ix+#12),l:assert $==getsize('res 7,(ix+#12),l')" \ +":bank:res 7,(ix+#12):assert $==getsize('res 7,(ix+#12)'):bank:res 7,(ix+#12),a:assert $==getsize('res 7,(ix+#12),a'):bank:set 0,(ix+#12),b:assert $==getsize('set 0,(ix+#12),b')" \ +":bank:set 0,(ix+#12),c:assert $==getsize('set 0,(ix+#12),c'):bank:set 0,(ix+#12),d:assert $==getsize('set 0,(ix+#12),d'):bank:set 0,(ix+#12),e:assert $==getsize('set 0,(ix+#12),e')" \ +":bank:set 0,(ix+#12),h:assert $==getsize('set 0,(ix+#12),h'):bank:set 0,(ix+#12),l:assert $==getsize('set 0,(ix+#12),l'):bank:set 0,(ix+#12):assert $==getsize('set 0,(ix+#12)')" \ +":bank:set 0,(ix+#12),a:assert $==getsize('set 0,(ix+#12),a'):bank:set 1,(ix+#12),b:assert $==getsize('set 1,(ix+#12),b'):bank:set 1,(ix+#12),c:assert $==getsize('set 1,(ix+#12),c')" \ +":bank:set 1,(ix+#12),d:assert $==getsize('set 1,(ix+#12),d'):bank:set 1,(ix+#12),e:assert $==getsize('set 1,(ix+#12),e'):bank:set 1,(ix+#12),h:assert $==getsize('set 1,(ix+#12),h')" \ +":bank:set 1,(ix+#12),l:assert $==getsize('set 1,(ix+#12),l'):bank:set 1,(ix+#12):assert $==getsize('set 1,(ix+#12)'):bank:set 1,(ix+#12),a:assert $==getsize('set 1,(ix+#12),a')" \ +":bank:set 2,(ix+#12),b:assert $==getsize('set 2,(ix+#12),b'):bank:set 2,(ix+#12),c:assert $==getsize('set 2,(ix+#12),c'):bank:set 2,(ix+#12),d:assert $==getsize('set 2,(ix+#12),d')" \ +":bank:set 2,(ix+#12),e:assert $==getsize('set 2,(ix+#12),e'):bank:set 2,(ix+#12),h:assert $==getsize('set 2,(ix+#12),h'):bank:set 2,(ix+#12),l:assert $==getsize('set 2,(ix+#12),l')" \ +":bank:set 2,(ix+#12):assert $==getsize('set 2,(ix+#12)'):bank:set 2,(ix+#12),a:assert $==getsize('set 2,(ix+#12),a'):bank:set 3,(ix+#12),b:assert $==getsize('set 3,(ix+#12),b')" \ +":bank:set 3,(ix+#12),c:assert $==getsize('set 3,(ix+#12),c'):bank:set 3,(ix+#12),d:assert $==getsize('set 3,(ix+#12),d'):bank:set 3,(ix+#12),e:assert $==getsize('set 3,(ix+#12),e')" \ +":bank:set 3,(ix+#12),h:assert $==getsize('set 3,(ix+#12),h'):bank:set 3,(ix+#12),l:assert $==getsize('set 3,(ix+#12),l'):bank:set 3,(ix+#12):assert $==getsize('set 3,(ix+#12)')" \ +":bank:set 3,(ix+#12),a:assert $==getsize('set 3,(ix+#12),a'):bank:set 4,(ix+#12),b:assert $==getsize('set 4,(ix+#12),b'):bank:set 4,(ix+#12),c:assert $==getsize('set 4,(ix+#12),c')" \ +":bank:set 4,(ix+#12),d:assert $==getsize('set 4,(ix+#12),d'):bank:set 4,(ix+#12),e:assert $==getsize('set 4,(ix+#12),e'):bank:set 4,(ix+#12),h:assert $==getsize('set 4,(ix+#12),h')" \ +":bank:set 4,(ix+#12),l:assert $==getsize('set 4,(ix+#12),l'):bank:set 4,(ix+#12):assert $==getsize('set 4,(ix+#12)'):bank:set 4,(ix+#12),a:assert $==getsize('set 4,(ix+#12),a')" \ +":bank:set 5,(ix+#12),b:assert $==getsize('set 5,(ix+#12),b'):bank:set 5,(ix+#12),c:assert $==getsize('set 5,(ix+#12),c'):bank:set 5,(ix+#12),d:assert $==getsize('set 5,(ix+#12),d')" \ +":bank:set 5,(ix+#12),e:assert $==getsize('set 5,(ix+#12),e'):bank:set 5,(ix+#12),h:assert $==getsize('set 5,(ix+#12),h'):bank:set 5,(ix+#12),l:assert $==getsize('set 5,(ix+#12),l')" \ +":bank:set 5,(ix+#12):assert $==getsize('set 5,(ix+#12)'):bank:set 5,(ix+#12),a:assert $==getsize('set 5,(ix+#12),a'):bank:set 6,(ix+#12),b:assert $==getsize('set 6,(ix+#12),b')" \ +":bank:set 6,(ix+#12),c:assert $==getsize('set 6,(ix+#12),c'):bank:set 6,(ix+#12),d:assert $==getsize('set 6,(ix+#12),d'):bank:set 6,(ix+#12),e:assert $==getsize('set 6,(ix+#12),e')" \ +":bank:set 6,(ix+#12),h:assert $==getsize('set 6,(ix+#12),h'):bank:set 6,(ix+#12),l:assert $==getsize('set 6,(ix+#12),l'):bank:set 6,(ix+#12):assert $==getsize('set 6,(ix+#12)')" \ +":bank:set 6,(ix+#12),a:assert $==getsize('set 6,(ix+#12),a'):bank:set 7,(ix+#12),b:assert $==getsize('set 7,(ix+#12),b'):bank:set 7,(ix+#12),c:assert $==getsize('set 7,(ix+#12),c')" \ +":bank:set 7,(ix+#12),d:assert $==getsize('set 7,(ix+#12),d'):bank:set 7,(ix+#12),e:assert $==getsize('set 7,(ix+#12),e'):bank:set 7,(ix+#12),h:assert $==getsize('set 7,(ix+#12),h')" \ +":bank:set 7,(ix+#12),l:assert $==getsize('set 7,(ix+#12),l'):bank:set 7,(ix+#12):assert $==getsize('set 7,(ix+#12)'):bank:set 7,(ix+#12),a:assert $==getsize('set 7,(ix+#12),a')" \ +":bank:add iy,bc:assert $==getsize('add iy,bc'):bank:add iy,de:assert $==getsize('add iy,de'):bank:ld iy,#1234:assert $==getsize('ld iy,#1234')" \ +":bank:ld (#1234),iy:assert $==getsize('ld (#1234),iy'):bank:inc iy:assert $==getsize('inc iy'):bank:inc yh:assert $==getsize('inc yh')" \ +":bank:dec yh:assert $==getsize('dec yh'):bank:ld yh,#12:assert $==getsize('ld yh,#12'):bank:add iy,iy:assert $==getsize('add iy,iy')" \ +":bank:ld iy,(#1234):assert $==getsize('ld iy,(#1234)'):bank:dec iy:assert $==getsize('dec iy'):bank:inc yl:assert $==getsize('inc yl')" \ +":bank:dec yl:assert $==getsize('dec yl'):bank:ld yl,#12:assert $==getsize('ld yl,#12'):bank:inc (iy+#12):assert $==getsize('inc (iy+#12)')" \ +":bank:dec (iy+#12):assert $==getsize('dec (iy+#12)'):bank:ld (iy+#12),#34:assert $==getsize('ld (iy+#12),#34'):bank:add iy,sp:assert $==getsize('add iy,sp')" \ +":bank:ld b,yh:assert $==getsize('ld b,yh'):bank:ld b,yl:assert $==getsize('ld b,yl'):bank:ld b,(iy+#12):assert $==getsize('ld b,(iy+#12)')" \ +":bank:ld c,yh:assert $==getsize('ld c,yh'):bank:ld c,yl:assert $==getsize('ld c,yl'):bank:ld c,(iy+#12):assert $==getsize('ld c,(iy+#12)')" \ +":bank:ld d,yh:assert $==getsize('ld d,yh'):bank:ld d,yl:assert $==getsize('ld d,yl'):bank:ld d,(iy+#12):assert $==getsize('ld d,(iy+#12)')" \ +":bank:ld e,yh:assert $==getsize('ld e,yh'):bank:ld e,yl:assert $==getsize('ld e,yl'):bank:ld e,(iy+#12):assert $==getsize('ld e,(iy+#12)')" \ +":bank:ld yh,b:assert $==getsize('ld yh,b'):bank:ld yh,c:assert $==getsize('ld yh,c'):bank:ld yh,d:assert $==getsize('ld yh,d')" \ +":bank:ld yh,e:assert $==getsize('ld yh,e'):bank:ld yh,yh:assert $==getsize('ld yh,yh'):bank:ld yh,yl:assert $==getsize('ld yh,yl')" \ +":bank:ld h,(iy+#12):assert $==getsize('ld h,(iy+#12)'):bank:ld yh,a:assert $==getsize('ld yh,a'):bank:ld yl,b:assert $==getsize('ld yl,b')" \ +":bank:ld yl,c:assert $==getsize('ld yl,c'):bank:ld yl,d:assert $==getsize('ld yl,d'):bank:ld yl,e:assert $==getsize('ld yl,e')" \ +":bank:ld yl,yh:assert $==getsize('ld yl,yh'):bank:ld yl,yl:assert $==getsize('ld yl,yl'):bank:ld l,(iy+#12):assert $==getsize('ld l,(iy+#12)')" \ +":bank:ld yl,a:assert $==getsize('ld yl,a'):bank:ld (iy+#12),b:assert $==getsize('ld (iy+#12),b'):bank:ld (iy+#12),c:assert $==getsize('ld (iy+#12),c')" \ +":bank:ld (iy+#12),d:assert $==getsize('ld (iy+#12),d'):bank:ld (iy+#12),e:assert $==getsize('ld (iy+#12),e'):bank:ld (iy+#12),h:assert $==getsize('ld (iy+#12),h')" \ +":bank:ld (iy+#12),l:assert $==getsize('ld (iy+#12),l'):bank:ld (iy+#12),a:assert $==getsize('ld (iy+#12),a'):bank:ld a,yh:assert $==getsize('ld a,yh')" \ +":bank:ld a,yl:assert $==getsize('ld a,yl'):bank:ld a,(iy+#12):assert $==getsize('ld a,(iy+#12)'):bank:add yh:assert $==getsize('add yh')" \ +":bank:add yl:assert $==getsize('add yl'):bank:add (iy+#12):assert $==getsize('add (iy+#12)'):bank:adc yh:assert $==getsize('adc yh')" \ +":bank:adc yl:assert $==getsize('adc yl'):bank:adc (iy+#12):assert $==getsize('adc (iy+#12)'):bank:sub yh:assert $==getsize('sub yh')" \ +":bank:sub yl:assert $==getsize('sub yl'):bank:sub (iy+#12):assert $==getsize('sub (iy+#12)'):bank:sbc yh:assert $==getsize('sbc yh')" \ +":bank:sbc yl:assert $==getsize('sbc yl'):bank:sbc (iy+#12):assert $==getsize('sbc (iy+#12)'):bank:and yh:assert $==getsize('and yh')" \ +":bank:and yl:assert $==getsize('and yl'):bank:and (iy+#12):assert $==getsize('and (iy+#12)'):bank:xor yh:assert $==getsize('xor yh')" \ +":bank:xor yl:assert $==getsize('xor yl'):bank:xor (iy+#12):assert $==getsize('xor (iy+#12)'):bank:or yh:assert $==getsize('or yh')" \ +":bank:or yl:assert $==getsize('or yl'):bank:or (iy+#12):assert $==getsize('or (iy+#12)'):bank:cp yh:assert $==getsize('cp yh')" \ +":bank:cp yl:assert $==getsize('cp yl'):bank:cp (iy+#12):assert $==getsize('cp (iy+#12)'):bank:pop iy:assert $==getsize('pop iy')" \ +":bank:ex (sp),iy:assert $==getsize('ex (sp),iy'):bank:push iy:assert $==getsize('push iy'):bank:jp (iy):assert $==getsize('jp (iy)')" \ +":bank:ld sp,iy:assert $==getsize('ld sp,iy'):bank:rlc (iy+#12),b:assert $==getsize('rlc (iy+#12),b'):bank:rlc (iy+#12),c:assert $==getsize('rlc (iy+#12),c')" \ +":bank:rlc (iy+#12),d:assert $==getsize('rlc (iy+#12),d'):bank:rlc (iy+#12),e:assert $==getsize('rlc (iy+#12),e'):bank:rlc (iy+#12),h:assert $==getsize('rlc (iy+#12),h')" \ +":bank:rlc (iy+#12),l:assert $==getsize('rlc (iy+#12),l'):bank:rlc (iy+#12):assert $==getsize('rlc (iy+#12)'):bank:rlc (iy+#12),a:assert $==getsize('rlc (iy+#12),a')" \ +":bank:rrc (iy+#12),b:assert $==getsize('rrc (iy+#12),b'):bank:rrc (iy+#12),c:assert $==getsize('rrc (iy+#12),c'):bank:rrc (iy+#12),d:assert $==getsize('rrc (iy+#12),d')" \ +":bank:rrc (iy+#12),e:assert $==getsize('rrc (iy+#12),e'):bank:rrc (iy+#12),h:assert $==getsize('rrc (iy+#12),h'):bank:rrc (iy+#12),l:assert $==getsize('rrc (iy+#12),l')" \ +":bank:rrc (iy+#12):assert $==getsize('rrc (iy+#12)'):bank:rrc (iy+#12),a:assert $==getsize('rrc (iy+#12),a'):bank:rl (iy+#12),b:assert $==getsize('rl (iy+#12),b')" \ +":bank:rl (iy+#12),c:assert $==getsize('rl (iy+#12),c'):bank:rl (iy+#12),d:assert $==getsize('rl (iy+#12),d'):bank:rl (iy+#12),e:assert $==getsize('rl (iy+#12),e')" \ +":bank:rl (iy+#12),h:assert $==getsize('rl (iy+#12),h'):bank:rl (iy+#12),l:assert $==getsize('rl (iy+#12),l'):bank:rl (iy+#12):assert $==getsize('rl (iy+#12)')" \ +":bank:rl (iy+#12),a:assert $==getsize('rl (iy+#12),a'):bank:rr (iy+#12),b:assert $==getsize('rr (iy+#12),b'):bank:rr (iy+#12),c:assert $==getsize('rr (iy+#12),c')" \ +":bank:rr (iy+#12),d:assert $==getsize('rr (iy+#12),d'):bank:rr (iy+#12),e:assert $==getsize('rr (iy+#12),e'):bank:rr (iy+#12),h:assert $==getsize('rr (iy+#12),h')" \ +":bank:rr (iy+#12),l:assert $==getsize('rr (iy+#12),l'):bank:rr (iy+#12):assert $==getsize('rr (iy+#12)'):bank:rr (iy+#12),a:assert $==getsize('rr (iy+#12),a')" \ +":bank:sla (iy+#12),b:assert $==getsize('sla (iy+#12),b'):bank:sla (iy+#12),c:assert $==getsize('sla (iy+#12),c'):bank:sla (iy+#12),d:assert $==getsize('sla (iy+#12),d')" \ +":bank:sla (iy+#12),e:assert $==getsize('sla (iy+#12),e'):bank:sla (iy+#12),h:assert $==getsize('sla (iy+#12),h'):bank:sla (iy+#12),l:assert $==getsize('sla (iy+#12),l')" \ +":bank:sla (iy+#12):assert $==getsize('sla (iy+#12)'):bank:sla (iy+#12),a:assert $==getsize('sla (iy+#12),a'):bank:sra (iy+#12),b:assert $==getsize('sra (iy+#12),b')" \ +":bank:sra (iy+#12),c:assert $==getsize('sra (iy+#12),c'):bank:sra (iy+#12),d:assert $==getsize('sra (iy+#12),d'):bank:sra (iy+#12),e:assert $==getsize('sra (iy+#12),e')" \ +":bank:sra (iy+#12),h:assert $==getsize('sra (iy+#12),h'):bank:sra (iy+#12),l:assert $==getsize('sra (iy+#12),l'):bank:sra (iy+#12):assert $==getsize('sra (iy+#12)')" \ +":bank:sra (iy+#12),a:assert $==getsize('sra (iy+#12),a'):bank:sll (iy+#12),b:assert $==getsize('sll (iy+#12),b'):bank:sll (iy+#12),c:assert $==getsize('sll (iy+#12),c')" \ +":bank:sll (iy+#12),d:assert $==getsize('sll (iy+#12),d'):bank:sll (iy+#12),e:assert $==getsize('sll (iy+#12),e'):bank:sll (iy+#12),h:assert $==getsize('sll (iy+#12),h')" \ +":bank:sll (iy+#12),l:assert $==getsize('sll (iy+#12),l'):bank:sll (iy+#12):assert $==getsize('sll (iy+#12)'):bank:sll (iy+#12),a:assert $==getsize('sll (iy+#12),a')" \ +":bank:srl (iy+#12),b:assert $==getsize('srl (iy+#12),b'):bank:srl (iy+#12),c:assert $==getsize('srl (iy+#12),c'):bank:srl (iy+#12),d:assert $==getsize('srl (iy+#12),d')" \ +":bank:srl (iy+#12),e:assert $==getsize('srl (iy+#12),e'):bank:srl (iy+#12),h:assert $==getsize('srl (iy+#12),h'):bank:srl (iy+#12),l:assert $==getsize('srl (iy+#12),l')" \ +":bank:srl (iy+#12):assert $==getsize('srl (iy+#12)'):bank:srl (iy+#12),a:assert $==getsize('srl (iy+#12),a'):bank:bit 0,(iy+#12):assert $==getsize('bit 0,(iy+#12)')" \ +":bank:bit 1,(iy+#12):assert $==getsize('bit 1,(iy+#12)'):bank:bit 2,(iy+#12):assert $==getsize('bit 2,(iy+#12)'):bank:bit 3,(iy+#12):assert $==getsize('bit 3,(iy+#12)')" \ +":bank:bit 4,(iy+#12):assert $==getsize('bit 4,(iy+#12)'):bank:bit 5,(iy+#12):assert $==getsize('bit 5,(iy+#12)'):bank:bit 6,(iy+#12):assert $==getsize('bit 6,(iy+#12)')" \ +":bank:bit 7,(iy+#12):assert $==getsize('bit 7,(iy+#12)'):bank:res 0,(iy+#12),b:assert $==getsize('res 0,(iy+#12),b'):bank:res 0,(iy+#12),c:assert $==getsize('res 0,(iy+#12),c')" \ +":bank:res 0,(iy+#12),d:assert $==getsize('res 0,(iy+#12),d'):bank:res 0,(iy+#12),e:assert $==getsize('res 0,(iy+#12),e'):bank:res 0,(iy+#12),h:assert $==getsize('res 0,(iy+#12),h')" \ +":bank:res 0,(iy+#12),l:assert $==getsize('res 0,(iy+#12),l'):bank:res 0,(iy+#12):assert $==getsize('res 0,(iy+#12)'):bank:res 0,(iy+#12),a:assert $==getsize('res 0,(iy+#12),a')" \ +":bank:res 1,(iy+#12),b:assert $==getsize('res 1,(iy+#12),b'):bank:res 1,(iy+#12),c:assert $==getsize('res 1,(iy+#12),c'):bank:res 1,(iy+#12),d:assert $==getsize('res 1,(iy+#12),d')" \ +":bank:res 1,(iy+#12),e:assert $==getsize('res 1,(iy+#12),e'):bank:res 1,(iy+#12),h:assert $==getsize('res 1,(iy+#12),h'):bank:res 1,(iy+#12),l:assert $==getsize('res 1,(iy+#12),l')" \ +":bank:res 1,(iy+#12):assert $==getsize('res 1,(iy+#12)'):bank:res 1,(iy+#12),a:assert $==getsize('res 1,(iy+#12),a'):bank:res 2,(iy+#12),b:assert $==getsize('res 2,(iy+#12),b')" \ +":bank:res 2,(iy+#12),c:assert $==getsize('res 2,(iy+#12),c'):bank:res 2,(iy+#12),d:assert $==getsize('res 2,(iy+#12),d'):bank:res 2,(iy+#12),e:assert $==getsize('res 2,(iy+#12),e')" \ +":bank:res 2,(iy+#12),h:assert $==getsize('res 2,(iy+#12),h'):bank:res 2,(iy+#12),l:assert $==getsize('res 2,(iy+#12),l'):bank:res 2,(iy+#12):assert $==getsize('res 2,(iy+#12)')" \ +":bank:res 2,(iy+#12),a:assert $==getsize('res 2,(iy+#12),a'):bank:res 3,(iy+#12),b:assert $==getsize('res 3,(iy+#12),b'):bank:res 3,(iy+#12),c:assert $==getsize('res 3,(iy+#12),c')" \ +":bank:res 3,(iy+#12),d:assert $==getsize('res 3,(iy+#12),d'):bank:res 3,(iy+#12),e:assert $==getsize('res 3,(iy+#12),e'):bank:res 3,(iy+#12),h:assert $==getsize('res 3,(iy+#12),h')" \ +":bank:res 3,(iy+#12),l:assert $==getsize('res 3,(iy+#12),l'):bank:res 3,(iy+#12):assert $==getsize('res 3,(iy+#12)'):bank:res 3,(iy+#12),a:assert $==getsize('res 3,(iy+#12),a')" \ +":bank:res 4,(iy+#12),b:assert $==getsize('res 4,(iy+#12),b'):bank:res 4,(iy+#12),c:assert $==getsize('res 4,(iy+#12),c'):bank:res 4,(iy+#12),d:assert $==getsize('res 4,(iy+#12),d')" \ +":bank:res 4,(iy+#12),e:assert $==getsize('res 4,(iy+#12),e'):bank:res 4,(iy+#12),h:assert $==getsize('res 4,(iy+#12),h'):bank:res 4,(iy+#12),l:assert $==getsize('res 4,(iy+#12),l')" \ +":bank:res 4,(iy+#12):assert $==getsize('res 4,(iy+#12)'):bank:res 4,(iy+#12),a:assert $==getsize('res 4,(iy+#12),a'):bank:res 5,(iy+#12),b:assert $==getsize('res 5,(iy+#12),b')" \ +":bank:res 5,(iy+#12),c:assert $==getsize('res 5,(iy+#12),c'):bank:res 5,(iy+#12),d:assert $==getsize('res 5,(iy+#12),d'):bank:res 5,(iy+#12),e:assert $==getsize('res 5,(iy+#12),e')" \ +":bank:res 5,(iy+#12),h:assert $==getsize('res 5,(iy+#12),h'):bank:res 5,(iy+#12),l:assert $==getsize('res 5,(iy+#12),l'):bank:res 5,(iy+#12):assert $==getsize('res 5,(iy+#12)')" \ +":bank:res 5,(iy+#12),a:assert $==getsize('res 5,(iy+#12),a'):bank:res 6,(iy+#12),b:assert $==getsize('res 6,(iy+#12),b'):bank:res 6,(iy+#12),c:assert $==getsize('res 6,(iy+#12),c')" \ +":bank:res 6,(iy+#12),d:assert $==getsize('res 6,(iy+#12),d'):bank:res 6,(iy+#12),e:assert $==getsize('res 6,(iy+#12),e'):bank:res 6,(iy+#12),h:assert $==getsize('res 6,(iy+#12),h')" \ +":bank:res 6,(iy+#12),l:assert $==getsize('res 6,(iy+#12),l'):bank:res 6,(iy+#12):assert $==getsize('res 6,(iy+#12)'):bank:res 6,(iy+#12),a:assert $==getsize('res 6,(iy+#12),a')" \ +":bank:res 7,(iy+#12),b:assert $==getsize('res 7,(iy+#12),b'):bank:res 7,(iy+#12),c:assert $==getsize('res 7,(iy+#12),c'):bank:res 7,(iy+#12),d:assert $==getsize('res 7,(iy+#12),d')" \ +":bank:res 7,(iy+#12),e:assert $==getsize('res 7,(iy+#12),e'):bank:res 7,(iy+#12),h:assert $==getsize('res 7,(iy+#12),h'):bank:res 7,(iy+#12),l:assert $==getsize('res 7,(iy+#12),l')" \ +":bank:res 7,(iy+#12):assert $==getsize('res 7,(iy+#12)'):bank:res 7,(iy+#12),a:assert $==getsize('res 7,(iy+#12),a'):bank:set 0,(iy+#12),b:assert $==getsize('set 0,(iy+#12),b')" \ +":bank:set 0,(iy+#12),c:assert $==getsize('set 0,(iy+#12),c'):bank:set 0,(iy+#12),d:assert $==getsize('set 0,(iy+#12),d'):bank:set 0,(iy+#12),e:assert $==getsize('set 0,(iy+#12),e')" \ +":bank:set 0,(iy+#12),h:assert $==getsize('set 0,(iy+#12),h'):bank:set 0,(iy+#12),l:assert $==getsize('set 0,(iy+#12),l'):bank:set 0,(iy+#12):assert $==getsize('set 0,(iy+#12)')" \ +":bank:set 1,(iy+#12),d:assert $==getsize('set 1,(iy+#12),d'):bank:set 1,(iy+#12),e:assert $==getsize('set 1,(iy+#12),e'):bank:set 1,(iy+#12),h:assert $==getsize('set 1,(iy+#12),h')" \ +":bank:set 1,(iy+#12),l:assert $==getsize('set 1,(iy+#12),l'):bank:set 1,(iy+#12):assert $==getsize('set 1,(iy+#12)'):bank:set 1,(iy+#12),a:assert $==getsize('set 1,(iy+#12),a')" \ +":bank:set 2,(iy+#12),b:assert $==getsize('set 2,(iy+#12),b'):bank:set 2,(iy+#12),c:assert $==getsize('set 2,(iy+#12),c'):bank:set 2,(iy+#12),d:assert $==getsize('set 2,(iy+#12),d')" \ +":bank:set 2,(iy+#12),e:assert $==getsize('set 2,(iy+#12),e'):bank:set 2,(iy+#12),h:assert $==getsize('set 2,(iy+#12),h'):bank:set 2,(iy+#12),l:assert $==getsize('set 2,(iy+#12),l')" \ +":bank:set 2,(iy+#12):assert $==getsize('set 2,(iy+#12)'):bank:set 2,(iy+#12),a:assert $==getsize('set 2,(iy+#12),a'):bank:set 3,(iy+#12),b:assert $==getsize('set 3,(iy+#12),b')" \ +":bank:set 3,(iy+#12),c:assert $==getsize('set 3,(iy+#12),c'):bank:set 3,(iy+#12),d:assert $==getsize('set 3,(iy+#12),d'):bank:set 3,(iy+#12),e:assert $==getsize('set 3,(iy+#12),e')" \ +":bank:set 3,(iy+#12),h:assert $==getsize('set 3,(iy+#12),h'):bank:set 3,(iy+#12),l:assert $==getsize('set 3,(iy+#12),l'):bank:set 3,(iy+#12):assert $==getsize('set 3,(iy+#12)')" \ +":bank:set 3,(iy+#12),a:assert $==getsize('set 3,(iy+#12),a'):bank:set 4,(iy+#12),b:assert $==getsize('set 4,(iy+#12),b'):bank:set 4,(iy+#12),c:assert $==getsize('set 4,(iy+#12),c')" \ +":bank:set 4,(iy+#12),d:assert $==getsize('set 4,(iy+#12),d'):bank:set 4,(iy+#12),e:assert $==getsize('set 4,(iy+#12),e'):bank:set 4,(iy+#12),h:assert $==getsize('set 4,(iy+#12),h')" \ +":bank:set 4,(iy+#12),l:assert $==getsize('set 4,(iy+#12),l'):bank:set 4,(iy+#12):assert $==getsize('set 4,(iy+#12)'):bank:set 4,(iy+#12),a:assert $==getsize('set 4,(iy+#12),a')" \ +":bank:set 5,(iy+#12),b:assert $==getsize('set 5,(iy+#12),b'):bank:set 5,(iy+#12),c:assert $==getsize('set 5,(iy+#12),c'):bank:set 5,(iy+#12),d:assert $==getsize('set 5,(iy+#12),d')" \ +":bank:set 5,(iy+#12),e:assert $==getsize('set 5,(iy+#12),e'):bank:set 5,(iy+#12),h:assert $==getsize('set 5,(iy+#12),h'):bank:set 5,(iy+#12),l:assert $==getsize('set 5,(iy+#12),l')" \ +":bank:set 5,(iy+#12):assert $==getsize('set 5,(iy+#12)'):bank:set 5,(iy+#12),a:assert $==getsize('set 5,(iy+#12),a'):bank:set 6,(ix+#12),c:assert $==getsize('set 6,(ix+#12),c')" \ +":bank:set 6,(ix+#12),d:assert $==getsize('set 6,(ix+#12),d'):bank:set 6,(ix+#12),e:assert $==getsize('set 6,(ix+#12),e'):bank:set 6,(ix+#12),h:assert $==getsize('set 6,(ix+#12),h')" \ +":bank:set 6,(ix+#12),l:assert $==getsize('set 6,(ix+#12),l'):bank:set 6,(ix+#12):assert $==getsize('set 6,(ix+#12)'):bank:set 6,(ix+#12),a:assert $==getsize('set 6,(ix+#12),a')" \ +":bank:set 7,(ix+#12),b:assert $==getsize('set 7,(ix+#12),b'):bank:set 7,(ix+#12),c:assert $==getsize('set 7,(ix+#12),c'):bank:set 7,(ix+#12),d:assert $==getsize('set 7,(ix+#12),d')" \ +":bank:set 7,(ix+#12),e:assert $==getsize('set 7,(ix+#12),e'):bank:set 7,(ix+#12),h:assert $==getsize('set 7,(ix+#12),h'):bank:set 7,(ix+#12),l:assert $==getsize('set 7,(ix+#12),l')" \ +":bank:set 7,(ix+#12):assert $==getsize('set 7,(ix+#12)'):bank:set 7,(ix+#12),a:assert $==getsize('set 7,(ix+#12),a'):bank:add iy,bc:assert $==getsize('add iy,bc')" \ +":bank:add iy,de:assert $==getsize('add iy,de'):bank:ld iy,#1234:assert $==getsize('ld iy,#1234'):bank:ld (#1234),iy:assert $==getsize('ld (#1234),iy')" \ +":bank:inc iy:assert $==getsize('inc iy'):bank:inc yh:assert $==getsize('inc yh'):bank:dec yh:assert $==getsize('dec yh')" \ +":bank:ld yh,#12:assert $==getsize('ld yh,#12'):bank:add iy,iy:assert $==getsize('add iy,iy'):bank:ld iy,(#1234):assert $==getsize('ld iy,(#1234)')" \ +":bank:dec iy:assert $==getsize('dec iy'):bank:inc yl:assert $==getsize('inc yl'):bank:dec yl:assert $==getsize('dec yl')" \ +":bank:ld yl,#12:assert $==getsize('ld yl,#12'):bank:inc (iy+#12):assert $==getsize('inc (iy+#12)'):bank:dec (iy+#12):assert $==getsize('dec (iy+#12)')" \ +":bank:ld (iy+#12),#34:assert $==getsize('ld (iy+#12),#34'):bank:add iy,sp:assert $==getsize('add iy,sp'):bank:ld b,yh:assert $==getsize('ld b,yh')" \ +":bank:ld b,yl:assert $==getsize('ld b,yl'):bank:ld b,(iy+#12):assert $==getsize('ld b,(iy+#12)'):bank:ld c,yh:assert $==getsize('ld c,yh')" \ +":bank:ld c,yl:assert $==getsize('ld c,yl'):bank:ld c,(iy+#12):assert $==getsize('ld c,(iy+#12)'):bank:ld d,yh:assert $==getsize('ld d,yh')" \ +":bank:ld d,yl:assert $==getsize('ld d,yl'):bank:ld d,(iy+#12):assert $==getsize('ld d,(iy+#12)'):bank:ld e,yh:assert $==getsize('ld e,yh')" \ +":bank:ld e,yl:assert $==getsize('ld e,yl'):bank:ld e,(iy+#12):assert $==getsize('ld e,(iy+#12)'):bank:ld yh,b:assert $==getsize('ld yh,b')" \ +":bank:ld yh,c:assert $==getsize('ld yh,c'):bank:ld yh,d:assert $==getsize('ld yh,d'):bank:ld yh,e:assert $==getsize('ld yh,e')" \ +":bank:ld yh,yh:assert $==getsize('ld yh,yh'):bank:ld yh,yl:assert $==getsize('ld yh,yl'):bank:ld h,(iy+#12):assert $==getsize('ld h,(iy+#12)')" \ +":bank:ld yh,a:assert $==getsize('ld yh,a'):bank:ld yl,b:assert $==getsize('ld yl,b'):bank:ld yl,c:assert $==getsize('ld yl,c')" \ +":bank:ld yl,d:assert $==getsize('ld yl,d'):bank:ld yl,e:assert $==getsize('ld yl,e'):bank:ld yl,yh:assert $==getsize('ld yl,yh')" \ +":bank:ld yl,yl:assert $==getsize('ld yl,yl'):bank:ld l,(iy+#12):assert $==getsize('ld l,(iy+#12)'):bank:ld yl,a:assert $==getsize('ld yl,a')" \ +":bank:ld (iy+#12),b:assert $==getsize('ld (iy+#12),b'):bank:ld (iy+#12),c:assert $==getsize('ld (iy+#12),c'):bank:ld (iy+#12),d:assert $==getsize('ld (iy+#12),d')" \ +":bank:ld (iy+#12),e:assert $==getsize('ld (iy+#12),e'):bank:ld (iy+#12),h:assert $==getsize('ld (iy+#12),h'):bank:ld (iy+#12),l:assert $==getsize('ld (iy+#12),l')" \ +":bank:ld (iy+#12),a:assert $==getsize('ld (iy+#12),a'):bank:ld a,yh:assert $==getsize('ld a,yh'):bank:ld a,yl:assert $==getsize('ld a,yl')" \ +":bank:ld a,(iy+#12):assert $==getsize('ld a,(iy+#12)'):bank:add yh:assert $==getsize('add yh'):bank:add yl:assert $==getsize('add yl')" \ +":bank:add (iy+#12):assert $==getsize('add (iy+#12)'):bank:adc yh:assert $==getsize('adc yh'):bank:adc yl:assert $==getsize('adc yl')" \ +":bank:adc (iy+#12):assert $==getsize('adc (iy+#12)'):bank:sub yh:assert $==getsize('sub yh'):bank:sub yl:assert $==getsize('sub yl')" \ +":bank:sub (iy+#12):assert $==getsize('sub (iy+#12)'):bank:sbc yh:assert $==getsize('sbc yh'):bank:sbc yl:assert $==getsize('sbc yl')" \ +":bank:sbc (iy+#12):assert $==getsize('sbc (iy+#12)'):bank:and yh:assert $==getsize('and yh'):bank:and yl:assert $==getsize('and yl')" \ +":bank:and (iy+#12):assert $==getsize('and (iy+#12)'):bank:xor yh:assert $==getsize('xor yh'):bank:xor yl:assert $==getsize('xor yl')" \ +":bank:xor (iy+#12):assert $==getsize('xor (iy+#12)'):bank:or yh:assert $==getsize('or yh'):bank:or yl:assert $==getsize('or yl')" \ +":bank:or (iy+#12):assert $==getsize('or (iy+#12)'):bank:cp yh:assert $==getsize('cp yh'):bank:cp yl:assert $==getsize('cp yl')" \ +":bank:cp (iy+#12):assert $==getsize('cp (iy+#12)'):bank:pop iy:assert $==getsize('pop iy'):bank:ex (sp),iy:assert $==getsize('ex (sp),iy')" \ +":bank:push iy:assert $==getsize('push iy'):bank:jp (iy):assert $==getsize('jp (iy)'):bank:ld sp,iy:assert $==getsize('ld sp,iy')" \ +":bank:rlc (iy+#12),b:assert $==getsize('rlc (iy+#12),b'):bank:rlc (iy+#12),c:assert $==getsize('rlc (iy+#12),c'):bank:rlc (iy+#12),d:assert $==getsize('rlc (iy+#12),d')" \ +":bank:rlc (iy+#12),e:assert $==getsize('rlc (iy+#12),e'):bank:rlc (iy+#12),h:assert $==getsize('rlc (iy+#12),h'):bank:rlc (iy+#12),l:assert $==getsize('rlc (iy+#12),l')" \ +":bank:rlc (iy+#12):assert $==getsize('rlc (iy+#12)'):bank:rlc (iy+#12),a:assert $==getsize('rlc (iy+#12),a'):bank:rrc (iy+#12),b:assert $==getsize('rrc (iy+#12),b')" \ +":bank:rrc (iy+#12),c:assert $==getsize('rrc (iy+#12),c'):bank:rrc (iy+#12),d:assert $==getsize('rrc (iy+#12),d'):bank:rrc (iy+#12),e:assert $==getsize('rrc (iy+#12),e')" \ +":bank:rrc (iy+#12),h:assert $==getsize('rrc (iy+#12),h'):bank:rrc (iy+#12),l:assert $==getsize('rrc (iy+#12),l'):bank:rrc (iy+#12):assert $==getsize('rrc (iy+#12)')" \ +":bank:rrc (iy+#12),a:assert $==getsize('rrc (iy+#12),a'):bank:rl (iy+#12),b:assert $==getsize('rl (iy+#12),b'):bank:rl (iy+#12),c:assert $==getsize('rl (iy+#12),c')" \ +":bank:rl (iy+#12),d:assert $==getsize('rl (iy+#12),d'):bank:rl (iy+#12),e:assert $==getsize('rl (iy+#12),e'):bank:rl (iy+#12),h:assert $==getsize('rl (iy+#12),h')" \ +":bank:rl (iy+#12),l:assert $==getsize('rl (iy+#12),l'):bank:rl (iy+#12):assert $==getsize('rl (iy+#12)'):bank:rl (iy+#12),a:assert $==getsize('rl (iy+#12),a')" \ +":bank:rr (iy+#12),b:assert $==getsize('rr (iy+#12),b'):bank:rr (iy+#12),c:assert $==getsize('rr (iy+#12),c'):bank:rr (iy+#12),d:assert $==getsize('rr (iy+#12),d')" \ +":bank:rr (iy+#12),e:assert $==getsize('rr (iy+#12),e'):bank:rr (iy+#12),h:assert $==getsize('rr (iy+#12),h'):bank:rr (iy+#12),l:assert $==getsize('rr (iy+#12),l')" \ +":bank:rr (iy+#12):assert $==getsize('rr (iy+#12)'):bank:rr (iy+#12),a:assert $==getsize('rr (iy+#12),a'):bank:sla (iy+#12),b:assert $==getsize('sla (iy+#12),b')" \ +":bank:sla (iy+#12),c:assert $==getsize('sla (iy+#12),c'):bank:sla (iy+#12),d:assert $==getsize('sla (iy+#12),d'):bank:sla (iy+#12),e:assert $==getsize('sla (iy+#12),e')" \ +":bank:sla (iy+#12),h:assert $==getsize('sla (iy+#12),h'):bank:sla (iy+#12),l:assert $==getsize('sla (iy+#12),l'):bank:sla (iy+#12):assert $==getsize('sla (iy+#12)')" \ +":bank:sla (iy+#12),a:assert $==getsize('sla (iy+#12),a'):bank:sra (iy+#12),b:assert $==getsize('sra (iy+#12),b'):bank:sra (iy+#12),c:assert $==getsize('sra (iy+#12),c')" \ +":bank:sra (iy+#12),d:assert $==getsize('sra (iy+#12),d'):bank:sra (iy+#12),e:assert $==getsize('sra (iy+#12),e'):bank:sra (iy+#12),h:assert $==getsize('sra (iy+#12),h')" \ +":bank:sra (iy+#12),l:assert $==getsize('sra (iy+#12),l'):bank:sra (iy+#12):assert $==getsize('sra (iy+#12)'):bank:sra (iy+#12),a:assert $==getsize('sra (iy+#12),a')" \ +":bank:sll (iy+#12),b:assert $==getsize('sll (iy+#12),b'):bank:sll (iy+#12),c:assert $==getsize('sll (iy+#12),c'):bank:sll (iy+#12),d:assert $==getsize('sll (iy+#12),d')" \ +":bank:sll (iy+#12),e:assert $==getsize('sll (iy+#12),e'):bank:sll (iy+#12),h:assert $==getsize('sll (iy+#12),h'):bank:sll (iy+#12),l:assert $==getsize('sll (iy+#12),l')" \ +":bank:sll (iy+#12):assert $==getsize('sll (iy+#12)'):bank:sll (iy+#12),a:assert $==getsize('sll (iy+#12),a'):bank:srl (iy+#12),b:assert $==getsize('srl (iy+#12),b')" \ +":bank:srl (iy+#12),c:assert $==getsize('srl (iy+#12),c'):bank:srl (iy+#12),d:assert $==getsize('srl (iy+#12),d'):bank:srl (iy+#12),e:assert $==getsize('srl (iy+#12),e')" \ +":bank:srl (iy+#12),h:assert $==getsize('srl (iy+#12),h'):bank:srl (iy+#12),l:assert $==getsize('srl (iy+#12),l'):bank:srl (iy+#12):assert $==getsize('srl (iy+#12)')" \ +":bank:srl (iy+#12),a:assert $==getsize('srl (iy+#12),a'):bank:bit 0,(iy+#12):assert $==getsize('bit 0,(iy+#12)'):bank:bit 1,(iy+#12):assert $==getsize('bit 1,(iy+#12)')" \ +":bank:bit 2,(iy+#12):assert $==getsize('bit 2,(iy+#12)'):bank:bit 3,(iy+#12):assert $==getsize('bit 3,(iy+#12)'):bank:bit 4,(iy+#12):assert $==getsize('bit 4,(iy+#12)')" \ +":bank:bit 5,(iy+#12):assert $==getsize('bit 5,(iy+#12)'):bank:bit 6,(iy+#12):assert $==getsize('bit 6,(iy+#12)'):bank:bit 7,(iy+#12):assert $==getsize('bit 7,(iy+#12)')" \ +":bank:res 0,(iy+#12),b:assert $==getsize('res 0,(iy+#12),b'):bank:res 0,(iy+#12),c:assert $==getsize('res 0,(iy+#12),c'):bank:res 0,(iy+#12),d:assert $==getsize('res 0,(iy+#12),d')" \ +":bank:res 0,(iy+#12),e:assert $==getsize('res 0,(iy+#12),e'):bank:res 0,(iy+#12),h:assert $==getsize('res 0,(iy+#12),h'):bank:res 0,(iy+#12),l:assert $==getsize('res 0,(iy+#12),l')" \ +":bank:res 0,(iy+#12):assert $==getsize('res 0,(iy+#12)'):bank:res 0,(iy+#12),a:assert $==getsize('res 0,(iy+#12),a'):bank:res 1,(iy+#12),b:assert $==getsize('res 1,(iy+#12),b')" \ +":bank:res 1,(iy+#12),c:assert $==getsize('res 1,(iy+#12),c'):bank:res 1,(iy+#12),d:assert $==getsize('res 1,(iy+#12),d'):bank:res 1,(iy+#12),e:assert $==getsize('res 1,(iy+#12),e')" \ +":bank:res 1,(iy+#12),h:assert $==getsize('res 1,(iy+#12),h'):bank:res 1,(iy+#12),l:assert $==getsize('res 1,(iy+#12),l'):bank:res 1,(iy+#12):assert $==getsize('res 1,(iy+#12)')" \ +":bank:res 1,(iy+#12),a:assert $==getsize('res 1,(iy+#12),a'):bank:res 2,(iy+#12),b:assert $==getsize('res 2,(iy+#12),b'):bank:res 2,(iy+#12),c:assert $==getsize('res 2,(iy+#12),c')" \ +":bank:res 2,(iy+#12),d:assert $==getsize('res 2,(iy+#12),d'):bank:res 2,(iy+#12),e:assert $==getsize('res 2,(iy+#12),e'):bank:res 2,(iy+#12),h:assert $==getsize('res 2,(iy+#12),h')" \ +":bank:res 2,(iy+#12),l:assert $==getsize('res 2,(iy+#12),l'):bank:res 2,(iy+#12):assert $==getsize('res 2,(iy+#12)'):bank:res 2,(iy+#12),a:assert $==getsize('res 2,(iy+#12),a')" \ +":bank:res 3,(iy+#12),b:assert $==getsize('res 3,(iy+#12),b'):bank:res 3,(iy+#12),c:assert $==getsize('res 3,(iy+#12),c'):bank:res 3,(iy+#12),d:assert $==getsize('res 3,(iy+#12),d')" \ +":bank:res 3,(iy+#12),e:assert $==getsize('res 3,(iy+#12),e'):bank:res 3,(iy+#12),h:assert $==getsize('res 3,(iy+#12),h'):bank:res 3,(iy+#12),l:assert $==getsize('res 3,(iy+#12),l')" \ +":bank:res 3,(iy+#12):assert $==getsize('res 3,(iy+#12)'):bank:res 3,(iy+#12),a:assert $==getsize('res 3,(iy+#12),a'):bank:res 4,(iy+#12),b:assert $==getsize('res 4,(iy+#12),b')" \ +":bank:res 4,(iy+#12),c:assert $==getsize('res 4,(iy+#12),c'):bank:res 4,(iy+#12),d:assert $==getsize('res 4,(iy+#12),d'):bank:res 4,(iy+#12),e:assert $==getsize('res 4,(iy+#12),e')" \ +":bank:res 4,(iy+#12),h:assert $==getsize('res 4,(iy+#12),h'):bank:res 4,(iy+#12),l:assert $==getsize('res 4,(iy+#12),l'):bank:res 4,(iy+#12):assert $==getsize('res 4,(iy+#12)')" \ +":bank:res 4,(iy+#12),a:assert $==getsize('res 4,(iy+#12),a'):bank:res 5,(iy+#12),b:assert $==getsize('res 5,(iy+#12),b'):bank:res 5,(iy+#12),c:assert $==getsize('res 5,(iy+#12),c')" \ +":bank:res 5,(iy+#12),d:assert $==getsize('res 5,(iy+#12),d'):bank:res 5,(iy+#12),e:assert $==getsize('res 5,(iy+#12),e'):bank:res 5,(iy+#12),h:assert $==getsize('res 5,(iy+#12),h')" \ +":bank:res 5,(iy+#12),l:assert $==getsize('res 5,(iy+#12),l'):bank:res 5,(iy+#12):assert $==getsize('res 5,(iy+#12)'):bank:res 5,(iy+#12),a:assert $==getsize('res 5,(iy+#12),a')" \ +":bank:res 6,(iy+#12),b:assert $==getsize('res 6,(iy+#12),b'):bank:res 6,(iy+#12),c:assert $==getsize('res 6,(iy+#12),c'):bank:res 6,(iy+#12),d:assert $==getsize('res 6,(iy+#12),d')" \ +":bank:res 6,(iy+#12),e:assert $==getsize('res 6,(iy+#12),e'):bank:res 6,(iy+#12),h:assert $==getsize('res 6,(iy+#12),h'):bank:res 6,(iy+#12),l:assert $==getsize('res 6,(iy+#12),l')" \ +":bank:res 6,(iy+#12):assert $==getsize('res 6,(iy+#12)'):bank:res 6,(iy+#12),a:assert $==getsize('res 6,(iy+#12),a'):bank:res 7,(iy+#12),b:assert $==getsize('res 7,(iy+#12),b')" \ +":bank:res 7,(iy+#12),c:assert $==getsize('res 7,(iy+#12),c'):bank:res 7,(iy+#12),d:assert $==getsize('res 7,(iy+#12),d'):bank:res 7,(iy+#12),e:assert $==getsize('res 7,(iy+#12),e')" \ +":bank:res 7,(iy+#12),h:assert $==getsize('res 7,(iy+#12),h'):bank:res 7,(iy+#12),l:assert $==getsize('res 7,(iy+#12),l'):bank:res 7,(iy+#12):assert $==getsize('res 7,(iy+#12)')" \ +":bank:res 7,(iy+#12),a:assert $==getsize('res 7,(iy+#12),a'):bank:set 0,(iy+#12),b:assert $==getsize('set 0,(iy+#12),b'):bank:set 0,(iy+#12),c:assert $==getsize('set 0,(iy+#12),c')" \ +":bank:set 0,(iy+#12),d:assert $==getsize('set 0,(iy+#12),d'):bank:set 0,(iy+#12),e:assert $==getsize('set 0,(iy+#12),e'):bank:set 0,(iy+#12),h:assert $==getsize('set 0,(iy+#12),h')" \ +":bank:set 0,(iy+#12),l:assert $==getsize('set 0,(iy+#12),l'):bank:set 0,(iy+#12):assert $==getsize('set 0,(iy+#12)'):bank:set 0,(iy+#12),a:assert $==getsize('set 0,(iy+#12),a')" \ +":bank:set 1,(iy+#12),b:assert $==getsize('set 1,(iy+#12),b'):bank:set 1,(iy+#12),c:assert $==getsize('set 1,(iy+#12),c'):bank:set 1,(iy+#12),d:assert $==getsize('set 1,(iy+#12),d')" \ +":bank:set 1,(iy+#12),e:assert $==getsize('set 1,(iy+#12),e'):bank:set 1,(iy+#12),h:assert $==getsize('set 1,(iy+#12),h'):bank:set 1,(iy+#12),l:assert $==getsize('set 1,(iy+#12),l')" \ +":bank:set 1,(iy+#12):assert $==getsize('set 1,(iy+#12)'):bank:set 1,(iy+#12),a:assert $==getsize('set 1,(iy+#12),a'):bank:set 2,(iy+#12),b:assert $==getsize('set 2,(iy+#12),b')" \ +":bank:set 2,(iy+#12),c:assert $==getsize('set 2,(iy+#12),c'):bank:set 2,(iy+#12),d:assert $==getsize('set 2,(iy+#12),d'):bank:set 2,(iy+#12),e:assert $==getsize('set 2,(iy+#12),e')" \ +":bank:set 2,(iy+#12),h:assert $==getsize('set 2,(iy+#12),h'):bank:set 2,(iy+#12),l:assert $==getsize('set 2,(iy+#12),l'):bank:set 2,(iy+#12):assert $==getsize('set 2,(iy+#12)')" \ +":bank:set 2,(iy+#12),a:assert $==getsize('set 2,(iy+#12),a'):bank:set 3,(iy+#12),b:assert $==getsize('set 3,(iy+#12),b'):bank:set 3,(iy+#12),c:assert $==getsize('set 3,(iy+#12),c')" \ +":bank:set 3,(iy+#12),d:assert $==getsize('set 3,(iy+#12),d'):bank:set 3,(iy+#12),e:assert $==getsize('set 3,(iy+#12),e'):bank:set 3,(iy+#12),h:assert $==getsize('set 3,(iy+#12),h')" \ +":bank:set 3,(iy+#12),l:assert $==getsize('set 3,(iy+#12),l'):bank:set 3,(iy+#12):assert $==getsize('set 3,(iy+#12)'):bank:set 3,(iy+#12),a:assert $==getsize('set 3,(iy+#12),a')" \ +":bank:set 4,(iy+#12),b:assert $==getsize('set 4,(iy+#12),b'):bank:set 4,(iy+#12),c:assert $==getsize('set 4,(iy+#12),c'):bank:set 4,(iy+#12),d:assert $==getsize('set 4,(iy+#12),d')" \ +":bank:set 4,(iy+#12),e:assert $==getsize('set 4,(iy+#12),e'):bank:set 4,(iy+#12),h:assert $==getsize('set 4,(iy+#12),h'):bank:set 4,(iy+#12),l:assert $==getsize('set 4,(iy+#12),l')" \ +":bank:set 4,(iy+#12):assert $==getsize('set 4,(iy+#12)'):bank:set 4,(iy+#12),a:assert $==getsize('set 4,(iy+#12),a'):bank:set 5,(iy+#12),b:assert $==getsize('set 5,(iy+#12),b')" \ +":bank:set 5,(iy+#12),c:assert $==getsize('set 5,(iy+#12),c'):bank:set 5,(iy+#12),d:assert $==getsize('set 5,(iy+#12),d'):bank:set 5,(iy+#12),e:assert $==getsize('set 5,(iy+#12),e')" \ +":bank:set 5,(iy+#12),h:assert $==getsize('set 5,(iy+#12),h'):bank:set 5,(iy+#12),l:assert $==getsize('set 5,(iy+#12),l'):bank:set 5,(iy+#12):assert $==getsize('set 5,(iy+#12)')" \ +":bank:set 5,(iy+#12),a:assert $==getsize('set 5,(iy+#12),a'):bank:set 6,(iy+#12),b:assert $==getsize('set 6,(iy+#12),b'):bank:set 6,(iy+#12),c:assert $==getsize('set 6,(iy+#12),c')" \ +":bank:set 6,(iy+#12),d:assert $==getsize('set 6,(iy+#12),d'):bank:set 6,(iy+#12),e:assert $==getsize('set 6,(iy+#12),e'):bank:set 6,(iy+#12),h:assert $==getsize('set 6,(iy+#12),h')" \ +":bank:set 6,(iy+#12),l:assert $==getsize('set 6,(iy+#12),l'):bank:set 6,(iy+#12):assert $==getsize('set 6,(iy+#12)'):bank:set 6,(iy+#12),a:assert $==getsize('set 6,(iy+#12),a')" \ +":bank:set 7,(iy+#12),b:assert $==getsize('set 7,(iy+#12),b'):bank:set 7,(iy+#12),c:assert $==getsize('set 7,(iy+#12),c'):bank:set 7,(iy+#12),d:assert $==getsize('set 7,(iy+#12),d')" \ +":bank:set 7,(iy+#12),e:assert $==getsize('set 7,(iy+#12),e'):bank:set 7,(iy+#12),h:assert $==getsize('set 7,(iy+#12),h'):bank:set 7,(iy+#12),l:assert $==getsize('set 7,(iy+#12),l')" \ +":bank:set 7,(iy+#12):assert $==getsize('set 7,(iy+#12)'):bank:set 7,(iy+#12),a:assert $==getsize('set 7,(iy+#12),a'):bank:set 7,(iy+#12),a:assert $==getsize('set 7,(iy+#12),a')" + +#define AUTOTEST_REPEAT3 "y=0: repeat 0: y+=1: rend: assert y==0: y=0: repeat 1: y+=1: rend: assert y==1:"\ + "y=0: repeat 5: y+=1: rend: assert y==5: y=1: repeat 5,x: assert y==x: y+=1: rend: y=2: repeat 5,x,2,2: assert x==y:"\ + "y+=2: rend: startingindex 5: y=5: repeat 2,x: assert x==y: y+=1: rend: startingindex 5,5: y=10: repeat 3,x,10: assert x==y: "\ + "y+=5: rend: startingindex: y=1: repeat 2,x: assert x==y: y+=1: rend: nop " + +#define AUTOTEST_SNASET "buildsna:bank 0:nop:"\ + ":snaset Z80_AF,0x1234 :snaset Z80_A,0x11 :snaset Z80_F,0x11 :snaset Z80_BC,0x11 :snaset Z80_B,0x11 :snaset Z80_C,0x11 :snaset Z80_DE,0x11 :snaset Z80_D,0x11"\ + ":snaset Z80_E,0x11 :snaset Z80_HL,0x11 :snaset Z80_H,0x11 :snaset Z80_L,0x11 :snaset Z80_R,0x11 :snaset Z80_I,0x11 :snaset Z80_IFF0,0x11 :snaset Z80_IFF1,0x11"\ + ":snaset Z80_IX,0x11 :snaset Z80_IY,0x11 :snaset Z80_IXL,0x11 :snaset Z80_IXH,0x11 :snaset Z80_IYL,0x11 :snaset Z80_IYH,0x11 :snaset Z80_SP,0x11 :snaset Z80_PC,0x11"\ + ":snaset Z80_IM,0x11 :snaset Z80_AFX,0x11 :snaset Z80_AX,0x11 :snaset Z80_FX,0x11 :snaset Z80_BCX,0x11 :snaset Z80_BX,0x11 :snaset Z80_CX,0x11 :snaset Z80_DEX,0x11"\ + ":snaset Z80_DX,0x11 :snaset Z80_EX,0x11 :snaset Z80_HLX,0x11 :snaset Z80_HX,0x11 :snaset Z80_LX,0x11 :snaset FDD_MOTOR,0x11 :snaset FDD_TRACK,0x11 :snaset PRNT_DATA,0x11"\ + ":snaset PPI_A,0x1 :snaset PPI_B,0x1 :snaset PPI_C,0x1 :snaset PPI_CTL,0x1 :snaset INT_NUM,0x1 :snaset INT_REQ,0x11 :snaset PSG_SEL,0x1 :snaset CRTC_SEL,0x1"\ + ":snaset CRTC_TYPE,0x1 :snaset CRTC_HCC,0x11 :snaset CRTC_CLC,0x11 :snaset CRTC_RLC,0x11 :snaset CRTC_VAC,0x11 :snaset CRTC_VSWC,0x11 :snaset CRTC_HSWC,0x11"\ + ":snaset CRTC_STATE,0x11 :snaset GA_VSC,0x11 :snaset GA_ISC,0x11 :snaset GA_PEN,0x11 :snaset GA_ROMCFG,0x11 :snaset GA_RAMCFG,0x11 :snaset ROM_UP,0x11"\ + ":snaset CRTC_REG,0,0x11 :snaset CRTC_REG,1,0x11 :snaset CRTC_REG,16,0x11 :snaset PSG_REG,0,0x11 :snaset PSG_REG,5,0x11 :snaset PSG_REG,15,0x11: bank : nop" + +#define AUTOTEST_INKCONV "assert s2h_ink(0)==0x54 :assert s2h_ink(1)==0x44 :assert s2h_ink(2)==0x55 :assert s2h_ink(3)==0x5C :assert s2h_ink(4)==0x58 :assert s2h_ink(5)==0x5D "\ +":assert s2h_ink(6)==0x4C :assert s2h_ink(7)==0x45 :assert s2h_ink(8)==0x4D :assert s2h_ink(9)==0x56 :assert s2h_ink(10)==0x46 :assert s2h_ink(11)==0x57 "\ +":assert s2h_ink(12)==0x5E :assert s2h_ink(13)==0x40 :assert soft2hard_ink(14)==0x5F :assert soft2hard_ink(15)==0x4E :assert soft2hard_ink(16)==0x47 "\ +":assert soft2hard_ink(17)==0x4F :assert soft2hard_ink(18)==0x52 :assert soft2hard_ink(19)==0x42 :assert soft2hard_ink(20)==0x53 :assert soft2hard_ink(21)==0x5A "\ +":assert soft2hard_ink(22)==0x59 :assert soft2hard_ink(23)==0x5B :assert soft2hard_ink(24)==0x4A :assert soft2hard_ink(25)==0x43 :assert soft2hard_ink(26)==0x4B "\ +":nop :assert h2s_ink(0)==13 :assert h2s_ink(0x40)==13 :assert h2s_ink(1)==13 :assert h2s_ink(2)==19 :assert h2s_ink(3)==25 :assert h2s_ink(4)==1 "\ +":assert h2s_ink(5)==7 :assert h2s_ink(6)==10 :assert h2s_ink(7)==16 :assert h2s_ink(8)==7 :assert h2s_ink(9)==25 :assert h2s_ink(10)==24 "\ +":assert h2s_ink(11)==26 :assert h2s_ink(12)==6 :assert h2s_ink(13)==8 :assert h2s_ink(14)==15 :assert hard2soft_ink(15)==17 :assert hard2soft_ink(16)==1 "\ +":assert hard2soft_ink(17)==19 :assert hard2soft_ink(18)==18 :assert hard2soft_ink(19)==20 :assert hard2soft_ink(20)==0 :assert hard2soft_ink(21)==2 "\ +":assert hard2soft_ink(22)==9 :assert hard2soft_ink(23)==11 :assert hard2soft_ink(24)==4 :assert hard2soft_ink(25)==22 :assert hard2soft_ink(26)==21 "\ +":assert hard2soft_ink(27)==23 :assert hard2soft_ink(28)==3 :assert hard2soft_ink(29)==5 :assert h2s_ink(30)==12 :assert h2s_ink(31)==14 :nop " + +#define AUTOTEST_ECPR1 "buildcpr extended : bank 32 : label1 : assert {bank}label1==32 : nop" + +#define AUTOTEST_BANKPROX " buildcpr: bank 0: grouik: .tape1: nop: ld hl,{bank}.tape2: bank 1: ld hl,{bank}.tape2: defw {bank}.tape2: .tape2: nop: " + +#define AUTOTEST_INTORAM1 " buildsna : bankset 0 : org #3FF8 : defb 'roudoudou in da house' " + +#define AUTOTEST_DEFMOD "nbt=0: module preums: label1 nop: label3: label4: ifdef label1:nbt+=1:endif: ifdef label3:nbt+=1:endif:"\ +"ifdef label4:nbt+=1:endif: ifndef label5:nbt+=1:endif: module deuze: label1 nop: label3: label5: ifdef label1:nbt+=1:endif:"\ +"ifdef label3:nbt+=1:endif: ifndef label4:nbt+=1:endif: ifdef label5:nbt+=1:endif: assert nbt==8:"\ +"module grouik: plop: ifused plop : glop=1 : endif:assert glop==1" + +#define AUTOTEST_GTILES "incbin 'autotest_include.raw',GTILES,4" +#define AUTOTEST_ITILES "incbin 'autotest_include.raw',ITILES,4" +#define AUTOTEST_GTILES_KO "incbin 'autotest_include.raw',GTILES,5" +#define AUTOTEST_ITILES_KO "incbin 'autotest_include.raw',ITILES,5" + + +struct s_autotest_keyword { + char *keywordtest; + int result; +}; + +struct s_autotest_keyword autotest_keyword[]={ + {"ld ly,h",1}, {"ld lx,h",1}, {"ld ly,l",1}, {"ld lx,l",1}, {"ld hy,h",1}, {"ld hx,h",1}, {"ld hy,l",1}, {"ld hx,l",1}, + {"nop",0},{"nop 2",0},{"nop a",1},{"nop (hl)",1},{"nop nop",1},{"nop grouik",1}, + {"ldir",0},{"ldir 5",1},{"ldir ldir",1},{"ldir (hl)",1},{"ldir a",1},{"ldir grouik",1}, + {"ldi",0},{"ldi 5",1},{"ldi ldi",1},{"ldi (hl)",1},{"ldi a",1},{"ldi grouik",1}, + {"lddr",0},{"lddr 5",1},{"lddr lddr",1},{"lddr (hl)",1},{"lddr a",1},{"lddr groudk",1}, + {"ldd",0},{"ldd 5",1},{"ldd ldd",1},{"ldd (hl)",1},{"ldd a",1},{"ldd groudk",1}, + {"jr $",0},{"jr 0",0},{"jr jr",1},{"jr (hl)",1},{"jr a",1}, + {"jr c,$",0},{"jr c,0",0},{"jr c,jr",1},{"jr c,(hl)",1},{"jr c,a",1}, + {"jr nc,$",0},{"jr nc,0",0},{"jr nc,jr",1},{"jr nc,(hl)",1},{"jr nc,a",1}, + {"jr z,$",0},{"jr 0",0},{"jr jr",1},{"jr (hl)",1},{"jr a",1}, + {"jr nz,$",0},{"jr 0",0},{"jr jr",1},{"jr (hl)",1},{"jr a",1}, + {"jp $",0},{"jp 0",0},{"jp jp",1},{"jp (hl)",0},{"jp (ix)",0},{"jp (iy)",0},{"jp (de)",1},{"jp a",1}, + {"jp (ix+5)",1}, {"jp (ix-5)",1}, {"jp (iy-5)",1}, {"jp (iy+5)",1}, + + // new unsupported test cases + {"jp (ix+1)",1},{"ld iy,(ix+1)",1},{"ld ix,(iy+1)",1},{"ld ix,(ix+2)",1},{"ld ixh,(ix+1)",1},{"ld sp,(ix+0)",1}, + {"ld (hl),(ix+0)",1},{"ld (iy+0),(iy+1)",1},{"ld (iy+0),(ix+1)",1},{"ld (ix+0),(iy+1)",1},{"ld (ix+0),(ix+1)",1}, + + {"jp c,$",0},{"jp c,0",0},{"jp c,jp",1}, {"jp c,(hl)",1}, {"jp c,(ix)",1}, {"jp c,(iy)",1},{"jp c,(de)",1},{"jp c,a",1}, + {"jp nc,$",0},{"jp nc,0",0},{"jp nc,jp",1},{"jp nc,(hl)",1},{"jp nc,(ix)",1},{"jp nc,(iy)",1},{"jp nc,(de)",1},{"jp nc,a",1}, + {"jp z,$",0},{"jp z,0",0},{"jp z,jp",1}, {"jp z,(hl)",1}, {"jp z,(ix)",1}, {"jp z,(iy)",1},{"jp z,(de)",1},{"jp z,a",1}, + {"jp nz,$",0},{"jp nz,0",0},{"jp nz,jp",1},{"jp nz,(hl)",1},{"jp nz,(ix)",1},{"jp nz,(iy)",1},{"jp nz,(de)",1},{"jp nz,a",1}, + {"jp pe,$",0},{"jp pe,0",0},{"jp pe,jp",1},{"jp pe,(hl)",1},{"jp pe,(ix)",1},{"jp pe,(iy)",1},{"jp pe,(de)",1},{"jp pe,a",1}, + {"jp po,$",0},{"jp po,0",0},{"jp po,jp",1},{"jp po,(hl)",1},{"jp po,(ix)",1},{"jp po,(iy)",1},{"jp po,(de)",1},{"jp po,a",1}, + {"jp p,$",0},{"jp p,0",0},{"jp p,jp",1}, {"jp p,(hl)",1}, {"jp p,(ix)",1}, {"jp p,(iy)",1},{"jp p,(de)",1},{"jp p,a",1}, + {"jp m,$",0},{"jp m,0",0},{"jp m,jp",1}, {"jp m,(hl)",1}, {"jp m,(ix)",1}, {"jp m,(iy)",1},{"jp m,(de)",1},{"jp m,a",1}, + {"ret",0},{"ret c",0},{"ret nc",0},{"ret pe",0},{"ret po",0},{"ret m",0},{"ret p",0},{"reti",0},{"ret ret",1},{"ret 5",1},{"ret (hl)",1},{"ret a",1}, + {"xor a",0},{"xor a,b",1},{"xor",1},{"xor (de)",1},{"xor (hl)",0},{"xor (bc)",1},{"xor (ix+0)",0},{"xor (iy+0)",0},{"xor xor",1}, + {"and a",0},{"and a,b",1},{"xor",1},{"and (de)",1},{"and (hl)",0},{"and (bc)",1},{"and (ix+0)",0},{"and (iy+0)",0},{"and xor",1}, + {"or a",0},{"or a,b",1},{"xor",1},{"or (de)",1},{"or (hl)",0},{"or (bc)",1},{"or (ix+0)",0},{"or (iy+0)",0},{"or xor",1}, + {"add",1},{"add a",0},{"add a,a",0},{"add add",1},{"add (hl)",0},{"add (de)",1},{"add xh",0},{"add grouik",1}, + {"add hl,ix",1},{"add hl,iy",1},{"add ix,iy",1},{"add iy,ix",1},{"add hl,0",1},{"add hl,grouik",1},{"add ix,hl",1},{"add iy,hl",1}, + {"adc",1},{"adc a",0},{"adc a,a",0},{"adc adc",1},{"adc (hl)",0},{"adc (de)",1},{"adc xh",0},{"adc grouik",1}, + {"adc hl,ix",1},{"adc hl,iy",1},{"adc ix,iy",1},{"adc iy,ix",1},{"adc hl,0",1},{"adc hl,grouik",1},{"adc ix,hl",1},{"adc iy,hl",1}, + {"sub",1},{"sub a",0},{"sub a,a",0},{"sub sub",1},{"sub (hl)",0},{"sub (de)",1},{"sub xh",0},{"sub grouik",1}, + {"sub hl,ix",1},{"sub hl,iy",1},{"sub ix,iy",1},{"sub iy,ix",1},{"sub hl,0",1},{"sub hl,grouik",1},{"sub ix,hl",1},{"sub iy,hl",1}, + {"sbc",1},{"sbc a",0},{"sbc a,a",0},{"sbc sbc",1},{"sbc (hl)",0},{"sbc (de)",1},{"sbc xh",0},{"sbc grouik",1}, + {"sbc hl,ix",1},{"sbc hl,iy",1},{"sbc ix,iy",1},{"sbc iy,ix",1},{"sbc hl,0",1},{"sbc hl,grouik",1},{"sbc ix,hl",1},{"sbc iy,hl",1}, + {"exx",0},{"exx hl",1},{"exx hl,de",1},{"exx af,af'",1},{"exx exx",1},{"exx 5",1}, + {"ex",1},{"ex af,af'",0},{"ex hl,de",0},{"ex hl,bc",1},{"ex hl,hl",1},{"ex hl,ix",1}, + {"cp",1},{"cp cp ",1},{"cp $",0},{"cp '$'",0},{"cp 'c'",0},{"cp 5",0},{"cp c",0},{"cp a,5",0},{"cp a,c",0},{"cp hl",1},{"cp (hl)",0},{"cp a,(hl)",0},{"cp (de)",1},{"cp de",1}, + {"cpi",0},{"cpi (hl)",1},{"cpi a",1},{"cpi 5",1}, + {"cpd",0},{"cpd (hl)",1},{"cpd a",1},{"cpd 5",1}, + {"cpir",0},{"cpir (hl)",1},{"cpir a",1},{"cpir 5",1}, + {"cpdr",0},{"cpdr (hl)",1},{"cpdr a",1},{"cpdr 5",1}, + {"call #1234",0},{"call call",1},{"call (hl)",1},{"call (ix)",1},{"call (iy)",1},{"call (de)",1},{"call hl",1},{"call bc",1},{"call a",1},{"call 5,5",1}, + {"rst 5",1},{"rst",1},{"rst 0",0},{"rst rst",1},{"rst (hl)",1},{"rst (ix)",1},{"rst (iy)",1},{"rst z",1},{"rst z,0",1}, + {"djnz",1},{"djnz $",0},{"djnz $,0",1},{"djnz djnz",1},{"djnz (hl)",1}, + {"djnz (ix)",1},{"djnz (iy)",1},{"djnz (bc)",1},{"djnz bc",1},{"djnz ix",1},{"djnz iy",1},{"djnz hl",1}, + {"push",1},{"push push",1},{"push pop",1},{"push af'",1},{"push (ix)",1},{"push (hl)",1},{"push (#1234)",1},{"push #1234",1}, + {"pop",1},{"pop pop",1},{"pop push",1},{"pop af'",1},{"pop (ix)",1},{"pop (hl)",1},{"pop (#1234)",1},{"pop #1234",1}, + {"set -1,a",1},{"set 9,a",1},{"set 0,xh",1},{"set 0,ix",1},{"set 0",1},{"set",1},{"set set",1},{"set 0,a,a",1},{"set 0,(ix+0),xh",1}, + {"bit -1,a",1},{"bit 9,a",1},{"bit 0,xh",1},{"bit 0,ix",1},{"bit 0",1},{"bit",1},{"bit bit",1},{"bit 0,a,a",1},{"bit 0,(ix+0),xh",1}, + {"res -1,a",1},{"res 9,a",1},{"res 0,xh",1},{"res 0,ix",1},{"res 0",1},{"res",1},{"res res",1},{"res 0,a,a",1},{"res 0,(ix+0),xh",1}, + {"srl",1},{"srl srl",1},{"srl hl",0}, /* srl hl is a kind of macro */ + {"rld a",1},{"rld (hl)",1},{"rld rld",1},{"rld 5",1},{"rld (ix)",1}, + {"rrd a",1},{"rrd (hl)",1},{"rrd rrd",1},{"rrd 5",1},{"rrd (ix)",1}, + {"cpl a",1},{"cpl (hl)",1},{"cpl cpl",1},{"cpl 0",1}, + {"daa daa daa",1},{"daa 0",1},{"daa (hl)",1}, + {"scf scf",1},{"scf 0",1},{"scf (hl)",1}, + {"ccf ccf",1},{"ccf 0",1},{"ccf (hl)",1}, + {"out",1},{"out out",1},{"out (c)",1},{"out (c),xh",1},{"out 0",1}, + {"out (c),hl",1},{"out (hl),c",1},{"out (c),(ix+0)",1},{"out (c),a,b",1}, + {"v nop:v0 nop:x=1:v{x} nop",0}, + {"outi 0",1},{"outi (hl)",1}, + {"otir 0",1},{"otir (hl)",1}, + {"otdr 0",1},{"otdr (hl)",1}, + {"outd 0",1},{"outd (hl)",1}, + {"in",1},{"in in",1},{"in (c)",1},{"in xh,(c)",1},{"in 0",1}, + {"in hl,(c)",1},{"in c,(hl)",1},{"in (c),(ix+0)",1},{"in a,(c),b",1}, + {"ini 0",1},{"ini (hl)",1}, + {"inir 0",1},{"inir (hl)",1}, + {"indr 0",1},{"indr (hl)",1}, + {"ind 0",1},{"ind (hl)",1}, + {"di 5",1},{"di di",1},{"di hl",1},{"di a",1}, + {"ei 5",1},{"ei ei",1},{"ei hl",1},{"ei a",1}, + {"im",1},{"im 3",1},{"im -1",1},{"im (hl)",1}, + {"halt 5",1},{"reti 5",1},{"retn 5",1},{"ld i,b",1},{"ld b,i",1}, + + {"repeat 5:nop:rend",0},{"repeat 100000:a=5:rend",1},{"repeat -5:nop:rend",1},{"repeat repeat:nop:rend",1}, + {"macro bidule:nop:mend:bidule",0},{"macro bidule:nop:macro glop:nop:mend:mend:bidule",1}, + {"macro bidule:nop",1},{"macro bidule:nop:mend:macro glop:nop:bidule",1}, + + + {"defb getnop(1)",1},{"defb getnop(-1)",1},{"defb getnop(10)",1},{"defb getnop(\"rien\")",1},{"defb getnop()",1},{"defb getnop(\"djNz\")",0}, + {"assert getnop('nop')==1 : nop",0}, + {"assert getnop('ldi')==5 : nop",0}, {"assert getnop('ldd')==5 : nop",0}, + {"assert getnop('dec a')==1 : nop",0}, {"assert getnop('dec b')==1 : nop",0}, {"assert getnop('dec c')==1 : nop",0}, + {"assert getnop('dec d')==1 : nop",0}, {"assert getnop('dec e')==1 : nop",0}, {"assert getnop('dec h')==1 : nop",0}, + {"assert getnop('dec l')==1 : nop",0}, {"assert getnop('dec xl')==2 : nop",0}, {"assert getnop('dec yl')==2 : nop",0}, + {"assert getnop('dec xh')==2 : nop",0}, {"assert getnop('dec yh')==2 : nop",0}, {"assert getnop('dec bc')==2 : nop",0}, + {"assert getnop('dec de')==2 : nop",0}, {"assert getnop('dec hl')==2 : nop",0}, {"assert getnop('dec sp')==2 : nop",0}, + {"assert getnop('dec ix')==3 : nop",0}, {"assert getnop('dec iy')==3 : nop",0}, {"assert getnop('dec (hl)')==3 : nop",0}, + {"assert getnop('dec (ix-50)')==6 : nop",0}, {"assert getnop('dec (iy+1)')==6 : nop",0}, + {"assert getnop('set 0,a')==2 : nop",0}, {"assert getnop('set 2,a')==2 : nop",0}, {"assert getnop('set 5,a')==2 : nop",0}, + {"assert getnop('set 0,b')==2 : nop",0}, {"assert getnop('set 0,c')==2 : nop",0}, {"assert getnop('set 0,d')==2 : nop",0}, + {"assert getnop('set 0,e')==2 : nop",0}, {"assert getnop('set 0,h')==2 : nop",0}, {"assert getnop('set 0,l')==2 : nop",0}, + {"assert getnop('set 0,(hl)')==4 : nop",0}, {"assert getnop('set 1,(ix+12),d')==7 : nop",0}, {"assert getnop('set 3,(iy-34),h')==7 : nop",0}, + {"assert getnop('res 0,a')==2 : nop",0}, {"assert getnop('res 2,a')==2 : nop",0}, {"assert getnop('res 5,a')==2 : nop",0}, + {"assert getnop('res 0,b')==2 : nop",0}, {"assert getnop('res 0,c')==2 : nop",0}, {"assert getnop('res 0,d')==2 : nop",0}, + {"assert getnop('res 0,e')==2 : nop",0}, {"assert getnop('res 0,h')==2 : nop",0}, {"assert getnop('res 0,l')==2 : nop",0}, + {"assert getnop('res 0,(hl)')==4 : nop",0}, {"assert getnop('res 1,(ix+12),d')==7 : nop",0}, {"assert getnop('res 3,(iy-34),h')==7 : nop",0}, + {"assert getnop('bit 0,a')==2 : nop",0}, {"assert getnop('bit 2,a')==2 : nop",0}, {"assert getnop('bit 5,a')==2 : nop",0}, + {"assert getnop('bit 0,b')==2 : nop",0}, {"assert getnop('bit 0,c')==2 : nop",0}, {"assert getnop('bit 0,d')==2 : nop",0}, + {"assert getnop('bit 0,e')==2 : nop",0}, {"assert getnop('bit 0,h')==2 : nop",0}, {"assert getnop('bit 0,l')==2 : nop",0}, + {"assert getnop('bit 0,(hl)')==3 : nop",0}, {"assert getnop('bit 1,(ix+12),d')==6 : nop",0}, {"assert getnop('bit 3,(iy-34),h')==6 : nop",0}, + {"assert getnop(\"ex af,af' \")==1 : nop",0}, {"assert getnop('ex hl,de ')==1 : nop",0}, {"assert getnop('ex de,hl ')==1 : nop",0}, + {"assert getnop('ex (sp),hl')==6 : nop",0}, {"assert getnop('ex (sp),ix ')==7 : nop",0}, {"assert getnop('ex (sp),iy ')==7 : nop",0}, + + {"assert getnop('exx ')==1 : nop",0}, {"assert getnop('rla ')==1 : nop",0}, {"assert getnop('rlca')==1 : nop",0}, {"assert getnop('rrca')==1 : nop",0}, + {"assert getnop('rra')==1 : nop",0}, {"assert getnop('ccf')==1 : nop",0}, {"assert getnop('daa')==1 : nop",0}, {"assert getnop('scf')==1 : nop",0}, + {"assert getnop('cpl')==1 : nop",0}, {"assert getnop('ei')==1 : nop",0}, {"assert getnop('di')==1 : nop",0}, {"assert getnop('im')==2 : nop",0}, + {"assert getnop('neg')==2 : nop",0}, {"assert getnop('rst')==4 : nop",0}, {"assert getnop('retn')==4 : nop",0}, {"assert getnop('reti')==4 : nop",0}, + {"assert getnop('rld')==5 : nop",0}, {"assert getnop('rrd')==5 : nop",0}, {"assert getnop('outi')==5 : nop",0}, {"assert getnop('outd')==5 : nop",0}, + {"assert getnop('ind')==5 : nop",0}, {"assert getnop('ini')==5 : nop",0}, {"assert getnop(\"ret\")==3 : nop",0}, {"assert getnop(\"ret nz\")==2 : nop",0}, + {"assert getnop(\"djNz\")==3 : nop",0}, {"assert getnop(\"jr\")==3 : nop",0}, {"assert getnop(\"jr nz\")==3 : nop",0}, {"assert getnop(\"jp (ix)\")==2 : nop",0}, + {"assert getnop(\"jp (iy)\")==2 : nop",0}, {"assert getnop(\"jp (hl)\")==1 : nop",0}, + + {"assert getnop(' pop af ' )==3 : nop",0}, {"assert getnop(' pop bc ' )==3 : nop",0}, {"assert getnop(' pop de ' )==3 : nop",0}, + {"assert getnop(' pop hl ' )==3 : nop",0}, {"assert getnop(' pop ix ' )==4 : nop",0}, {"assert getnop(' pop iy ' )==4 : nop",0}, + {"assert getnop(' push af ' )==4 : nop",0}, {"assert getnop(' push bc ' )==4 : nop",0}, {"assert getnop(' push de ' )==4 : nop",0}, + {"assert getnop(' push hl ' )==4 : nop",0}, {"assert getnop(' push ix ' )==5 : nop",0}, {"assert getnop(' push iy ' )==5 : nop",0}, + + {"assert getnop('add a,a')==1 : nop",0}, {"assert getnop('add a,b')==1 : nop",0}, {"assert getnop('add a,c')==1 : nop",0}, + {"assert getnop('add a,d')==1 : nop",0}, {"assert getnop('add a,e')==1 : nop",0}, {"assert getnop('add a,h')==1 : nop",0}, {"assert getnop('add a,l')==1 : nop",0}, + {"assert getnop('add a')==1 : nop",0}, {"assert getnop('add b')==1 : nop",0}, {"assert getnop('add c')==1 : nop",0}, + {"assert getnop('add d')==1 : nop",0}, {"assert getnop('add e')==1 : nop",0}, {"assert getnop('add h')==1 : nop",0}, {"assert getnop('add l')==1 : nop",0}, + {"assert getnop('add a,#12')==2 : nop",0}, {"assert getnop('add #12')==2 : nop",0}, {"assert getnop('add a,(hl)')==2 : nop",0}, + {"assert getnop('add (hl)')==2 : nop",0}, {"assert getnop('add a,xl')==2 : nop",0}, {"assert getnop('add xl')==2 : nop",0}, + {"assert getnop('add hl,bc')==3 : nop",0}, {"assert getnop('add hl,de')==3 : nop",0}, {"assert getnop('add hl,hl')==3 : nop",0}, {"assert getnop('add hl,sp')==3 : nop",0}, + {"assert getnop('add ix,bc')==4 : nop",0}, {"assert getnop('add ix,de')==4 : nop",0}, {"assert getnop('add ix,ix')==4 : nop",0}, {"assert getnop('add ix,sp')==4 : nop",0}, + {"assert getnop('add a,(ix+12)' )==5 : nop",0}, {"assert getnop('add (iy-102)' )==5 : nop",0}, + + {"assert getnop('adc a,a')==1 : nop",0}, {"assert getnop('adc a,b')==1 : nop",0}, {"assert getnop('adc a,c')==1 : nop",0}, + {"assert getnop('adc a,d')==1 : nop",0}, {"assert getnop('adc a,e')==1 : nop",0}, {"assert getnop('adc a,h')==1 : nop",0}, {"assert getnop('adc a,l')==1 : nop",0}, + {"assert getnop('adc a')==1 : nop",0}, {"assert getnop('adc b')==1 : nop",0}, {"assert getnop('adc c')==1 : nop",0}, + {"assert getnop('adc d')==1 : nop",0}, {"assert getnop('adc e')==1 : nop",0}, {"assert getnop('adc h')==1 : nop",0}, {"assert getnop('adc l')==1 : nop",0}, + {"assert getnop('adc a,#12')==2 : nop",0}, {"assert getnop('adc #12')==2 : nop",0}, {"assert getnop('adc a,(hl)')==2 : nop",0}, + {"assert getnop('adc (hl)')==2 : nop",0}, {"assert getnop('adc a,xl')==2 : nop",0}, {"assert getnop('adc xl')==2 : nop",0}, + {"assert getnop('adc hl,bc')==4 : nop",0}, {"assert getnop('adc hl,de')==4 : nop",0}, {"assert getnop('adc hl,hl')==4 : nop",0}, {"assert getnop('adc hl,sp')==4 : nop",0}, + {"assert getnop('adc a,(ix+12)' )==5 : nop",0}, {"assert getnop('adc (iy-102)' )==5 : nop",0}, + + {"assert getnop('sbc a,a')==1 : nop",0}, {"assert getnop('sbc a,b')==1 : nop",0}, {"assert getnop('sbc a,c')==1 : nop",0}, + {"assert getnop('sbc a,d')==1 : nop",0}, {"assert getnop('sbc a,e')==1 : nop",0}, {"assert getnop('sbc a,h')==1 : nop",0}, {"assert getnop('sbc a,l')==1 : nop",0}, + {"assert getnop('sbc a')==1 : nop",0}, {"assert getnop('sbc b')==1 : nop",0}, {"assert getnop('sbc c')==1 : nop",0}, + {"assert getnop('sbc d')==1 : nop",0}, {"assert getnop('sbc e')==1 : nop",0}, {"assert getnop('sbc h')==1 : nop",0}, {"assert getnop('sbc l')==1 : nop",0}, + {"assert getnop('sbc a,#12')==2 : nop",0}, {"assert getnop('sbc #12')==2 : nop",0}, {"assert getnop('sbc a,(hl)')==2 : nop",0}, + {"assert getnop('sbc (hl)')==2 : nop",0}, {"assert getnop('sbc a,xl')==2 : nop",0}, {"assert getnop('sbc xl')==2 : nop",0}, + {"assert getnop('sbc hl,bc')==4 : nop",0}, {"assert getnop('sbc hl,de')==4 : nop",0}, {"assert getnop('sbc hl,hl')==4 : nop",0}, {"assert getnop('sbc hl,sp')==4 : nop",0}, + {"assert getnop('sbc a,(ix+12)' )==5 : nop",0}, {"assert getnop('sbc (iy-102)' )==5 : nop",0}, + + {"assert getnop('sub a,a')==1 : nop",0}, {"assert getnop('sub a,b')==1 : nop",0}, {"assert getnop('sub a,c')==1 : nop",0}, + {"assert getnop('sub a,d')==1 : nop",0}, {"assert getnop('sub a,e')==1 : nop",0}, {"assert getnop('sub a,h')==1 : nop",0}, {"assert getnop('sub a,l')==1 : nop",0}, + {"assert getnop('sub a')==1 : nop",0}, {"assert getnop('sub b')==1 : nop",0}, {"assert getnop('sub c')==1 : nop",0}, + {"assert getnop('sub d')==1 : nop",0}, {"assert getnop('sub e')==1 : nop",0}, {"assert getnop('sub h')==1 : nop",0}, {"assert getnop('sub l')==1 : nop",0}, + {"assert getnop('sub a,#12')==2 : nop",0}, {"assert getnop('sub #12')==2 : nop",0}, {"assert getnop('sub a,(hl)')==2 : nop",0}, + {"assert getnop('sub (hl)')==2 : nop",0}, {"assert getnop('sub a,xl')==2 : nop",0}, {"assert getnop('sub xl')==2 : nop",0}, + {"assert getnop('sub a,(ix+12)' )==5 : nop",0}, {"assert getnop('sub (iy-102)' )==5 : nop",0}, + + {"assert getnop('out (c),a' )==4 : nop",0}, {"assert getnop('out (c),b' )==4 : nop",0}, {"assert getnop('out (c),c' )==4 : nop",0}, + {"assert getnop('out (c),d' )==4 : nop",0}, {"assert getnop('out (c),e' )==4 : nop",0}, {"assert getnop('out (c),h' )==4 : nop",0}, + {"assert getnop('out (c),l' )==4 : nop",0}, {"assert getnop('out (c),0' )==4 : nop",0}, {"assert getnop('out (12),a')==3 : nop",0}, + {"assert getnop('out (c),l : out (c),0 : out (12),a')==11 : nop",0}, + {"assert getnop('in a,(c)' )==4 : nop",0}, {"assert getnop('in b,(c)' )==4 : nop",0}, {"assert getnop('in a,(0)' )==3 : nop",0}, + {"assert getnop('in a,(0) : in a,(c)' )==7 : nop",0}, + + {"assert getnop('or a')==1 : nop",0}, {"assert getnop('or b')==1 : nop",0}, {"assert getnop('or c')==1 : nop",0}, + {"assert getnop('or d')==1 : nop",0}, {"assert getnop('or e')==1 : nop",0}, {"assert getnop('or h')==1 : nop",0}, + {"assert getnop('or l')==1 : nop",0}, {"assert getnop('or (hl)')==2 : nop",0}, {"assert getnop('or ixl')==2 : nop",0}, + {"assert getnop('or ixh')==2 : nop",0}, {"assert getnop('or xl')==2 : nop",0}, {"assert getnop('or xh')==2 : nop",0}, + {"assert getnop('or lx')==2 : nop",0}, {"assert getnop('or hx')==2 : nop",0}, {"assert getnop('or (ix+d)')==5 : nop",0}, + {"assert getnop('or (iy-d)')==5 : nop",0}, {"assert getnop('or a,(iy-d)')==5 : nop",0}, + {"assert getnop('xor a')==1 : nop",0}, {"assert getnop('xor b')==1 : nop",0}, {"assert getnop('xor c')==1 : nop",0}, + {"assert getnop('xor d')==1 : nop",0}, {"assert getnop('xor e')==1 : nop",0}, {"assert getnop('xor h')==1 : nop",0}, + {"assert getnop('xor l')==1 : nop",0}, {"assert getnop('xor (hl)')==2 : nop",0}, {"assert getnop('xor ixl')==2 : nop",0}, + {"assert getnop('xor ixh')==2 : nop",0}, {"assert getnop('xor xl')==2 : nop",0}, {"assert getnop('xor xh')==2 : nop",0}, + {"assert getnop('xor lx')==2 : nop",0}, {"assert getnop('xor hx')==2 : nop",0}, {"assert getnop('xor (ix+d)')==5 : nop",0}, + {"assert getnop('xor (iy-d)')==5 : nop",0}, {"assert getnop('xor a,(iy-d)')==5 : nop",0}, + {"assert getnop('and a')==1 : nop",0}, {"assert getnop('and b')==1 : nop",0}, {"assert getnop('and c')==1 : nop",0}, + {"assert getnop('and d')==1 : nop",0}, {"assert getnop('and e')==1 : nop",0}, {"assert getnop('and h')==1 : nop",0}, + {"assert getnop('and l')==1 : nop",0}, {"assert getnop('and (hl)')==2 : nop",0}, {"assert getnop('and ixl')==2 : nop",0}, + {"assert getnop('and ixh')==2 : nop",0}, {"assert getnop('and xl')==2 : nop",0}, {"assert getnop('and xh')==2 : nop",0}, + {"assert getnop('and lx')==2 : nop",0}, {"assert getnop('and hx')==2 : nop",0}, {"assert getnop('and (ix+d)')==5 : nop",0}, + {"assert getnop('and (iy-d)')==5 : nop",0}, {"assert getnop('and a,(iy-d)')==5 : nop",0}, + + {"assert getnop('rr a')==2 : nop",0}, {"assert getnop('rr b')==2 : nop",0}, {"assert getnop('rr (hl)')==4 : nop",0}, + {"assert getnop('rr (ix+5)')==7 : nop",0}, {"assert getnop('rr (iy-111)')==7 : nop",0}, {"assert getnop('rr (ix+2),b')==7 : nop",0}, + {"assert getnop('rl a')==2 : nop",0}, {"assert getnop('rl b')==2 : nop",0}, {"assert getnop('rl (hl)')==4 : nop",0}, + {"assert getnop('rl (ix+5)')==7 : nop",0}, {"assert getnop('rl (iy-111)')==7 : nop",0}, {"assert getnop('rl (ix+2),b')==7 : nop",0}, + {"assert getnop('rrc a')==2 : nop",0}, {"assert getnop('rrc b')==2 : nop",0}, {"assert getnop('rrc (hl)')==4 : nop",0}, + {"assert getnop('rrc (ix+5)')==7 : nop",0}, {"assert getnop('rrc (iy-111)')==7 : nop",0}, {"assert getnop('rrc (ix+2),b')==7 : nop",0}, + {"assert getnop('rlc a')==2 : nop",0}, {"assert getnop('rlc b')==2 : nop",0}, {"assert getnop('rlc (hl)')==4 : nop",0}, + {"assert getnop('rlc (ix+5)')==7 : nop",0}, {"assert getnop('rlc (iy-111)')==7 : nop",0}, {"assert getnop('rlc (ix+2),b')==7 : nop",0}, + {"assert getnop('sla a')==2 : nop",0}, {"assert getnop('sla b')==2 : nop",0}, {"assert getnop('sla (hl)')==4 : nop",0}, + {"assert getnop('sla (ix+5)')==7 : nop",0}, {"assert getnop('sla (iy-111)')==7 : nop",0}, {"assert getnop('sla (ix+2),b')==7 : nop",0}, + {"assert getnop('sra a')==2 : nop",0}, {"assert getnop('sra b')==2 : nop",0}, {"assert getnop('sra (hl)')==4 : nop",0}, + {"assert getnop('sra (ix+5)')==7 : nop",0}, {"assert getnop('sra (iy-111)')==7 : nop",0}, {"assert getnop('sra (ix+2),b')==7 : nop",0}, + {"assert getnop('sll a')==2 : nop",0}, {"assert getnop('sll b')==2 : nop",0}, {"assert getnop('sll (hl)')==4 : nop",0}, + {"assert getnop('sll (ix+5)')==7 : nop",0}, {"assert getnop('sll (iy-111)')==7 : nop",0}, {"assert getnop('sll (ix+2),b')==7 : nop",0}, + {"assert getnop('srl a')==2 : nop",0}, {"assert getnop('srl b')==2 : nop",0}, {"assert getnop('srl (hl)')==4 : nop",0}, + {"assert getnop('srl (ix+5)')==7 : nop",0}, {"assert getnop('srl (iy-111)')==7 : nop",0}, {"assert getnop('srl (ix+2),b')==7 : nop",0}, + + /* wrong snapshot settings */ + {"buildsna:bank 0:nop:snaset crtc_type",1}, + {"buildsna:bank 0:nop:snaset crtc_type,3,2",1}, + {"buildsna:bank 0:nop:snaset crtc_reg,3",1}, + {"buildsna:bank 0:nop:snaset crtc_reg,20,0",1}, + {"buildsna:bank 0:nop:snaset crtc_reg,-1,0",1}, + {"buildsna:bank 0:nop:snaset psg_reg,3",1}, + {"buildsna:bank 0:nop:snaset psg_reg,20,0",1}, + {"buildsna:bank 0:nop:snaset psg_reg,-1,0",1}, + {"buildsna:bank 0:nop:snaset ga_pal,3",1}, + {"buildsna:bank 0:nop:snaset ga_pal,20,0",1}, + {"buildsna:bank 0:nop:snaset ga_pal,-1,0",1}, + {"glop=rnd(5):nop",0},{"glop=rnd(0):nop",1},{"glop=rnd():nop",1},{"glop=rnd(-1):nop",1},{"pifou=8:glop=rnd(pifou):defb glop",0}, + /* wrong include usage */ + {"incbin",1},{"include",1},{"incbin'",1},{"include'",1},{"'include",1}, {"'incbin",1}, + {"incexo",1},{"inczx7",1},{"incaaa",0}, {"inc",1}, {"incl48",1},{"incl49",1},{"incapu",1},{"inclz4",1}, + {"incexo'",1},{"inczx7'",1},{"incaaa'",1}, {"inc'",1}, {"incl48'",1},{"incl49'",1},{"incapu'",1},{"inclz4'",1}, + {"incexb",0}, {"includee",0}, {"incexb'",1}, {"includee'",1}, + /* + {"",},{"",},{"",},{"",},{"",}, + {"",},{"",},{"",},{"",},{"",},{"",}, + {"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",}, + {"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",}, + {"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",}, + */ + {NULL,0} +}; + +void MiniDump(unsigned char *opcode, int opcodelen) { + #undef FUNC + #define FUNC "MiniDump" + + int i; + printf("%d byte%s to dump\n",opcodelen,opcodelen>1?"s":""); + for (i=0;i NOT ANYMORE + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing include on a missing file OK\n"); + + ret=RasmAssemble(AUTOTEST_BADINCLUDE,strlen(AUTOTEST_BADINCLUDE),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (bad include test)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing include filename on multiple lines OK\n"); + + ret=RasmAssemble(AUTOTEST_BADINCLUDE02,strlen(AUTOTEST_BADINCLUDE02),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (bad include test 2)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing wrong READ usage OK\n"); + + ret=RasmAssemble(AUTOTEST_BADINCBIN,strlen(AUTOTEST_BADINCBIN),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (bad incbin test)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing incbin filename on multiple lines OK\n"); + + ret=RasmAssemble(AUTOTEST_FORMAT,strlen(AUTOTEST_FORMAT),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (digit formats)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing digit formats OK\n"); + + /* Autotest assembling */ + ret=RasmAssemble(AUTOTEST_OPCODES,strlen(AUTOTEST_OPCODES),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (all opcodes)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing all opcodes OK\n"); + + /******************************************** + Autotest assembly options + *********************************************/ + + #define AUTOTEST_PARAM_AMPER "ld a,&10 : assert &10==#10" + memset(¶m,0,sizeof(struct s_parameter)); + param.noampersand=1; + ret=RasmAssembleInfoParam(AUTOTEST_PARAM_AMPER,strlen(AUTOTEST_PARAM_AMPER),&opcode,&opcodelen,&debug,¶m); + if (!ret) {} else {printf("Autotest %03d ERROR (testing compilation option -amper)\n",cpt);MiniDump(opcode,opcodelen);for (i=0;inberror;i++) printf("%d -> %s\n",i,debug->error[i].msg);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; + RasmFreeInfoStruct(debug); +printf("testing command line parameter -amper OK\n"); + + #define AUTOTEST_PARAM_MAXAM "aaa=10+5*3 : assert aaa==45 : nop" + memset(¶m,0,sizeof(struct s_parameter)); + param.rough=0.0; // 0.5 as default + ret=RasmAssembleInfoParam(AUTOTEST_PARAM_MAXAM,strlen(AUTOTEST_PARAM_MAXAM),&opcode,&opcodelen,&debug,¶m); + if (!ret) {} else {printf("Autotest %03d ERROR (testing compilation option -m)\n",cpt);MiniDump(opcode,opcodelen);for (i=0;inberror;i++) printf("%d -> %s\n",i,debug->error[i].msg);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; + RasmFreeInfoStruct(debug); +printf("testing command line parameter -m OK\n"); + + #define AUTOTEST_PARAM_DAMS ".grouik : djnz grouik" + memset(¶m,0,sizeof(struct s_parameter)); + param.dams=1; + ret=RasmAssembleInfoParam(AUTOTEST_PARAM_DAMS,strlen(AUTOTEST_PARAM_DAMS),&opcode,&opcodelen,&debug,¶m); + if (!ret) {} else {printf("Autotest %03d ERROR (testing compilation option -dams)\n",cpt);MiniDump(opcode,opcodelen);for (i=0;inberror;i++) printf("%d -> %s\n",i,debug->error[i].msg);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; + RasmFreeInfoStruct(debug); +printf("testing command line parameter -dams OK\n"); + + #define AUTOTEST_PARAM_PASMO "org #1234 : defw $,$" + memset(¶m,0,sizeof(struct s_parameter)); + param.pasmo=1; + ret=RasmAssembleInfoParam(AUTOTEST_PARAM_PASMO,strlen(AUTOTEST_PARAM_PASMO),&opcode,&opcodelen,&debug,¶m); + if (!ret && opcodelen==4 && opcode[0]==opcode[2] && opcode[1]==opcode[3]) {} else {printf("Autotest %03d ERROR (testing compilation option -pasmo)\n",cpt);MiniDump(opcode,opcodelen);for (i=0;inberror;i++) printf("%d -> %s\n",i,debug->error[i].msg);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; + RasmFreeInfoStruct(debug); +printf("testing command line parameter -pasmo OK\n"); + + #define AUTOTEST_PARAM_VOID "macro grouik : nop : mend : grouik" + memset(¶m,0,sizeof(struct s_parameter)); + param.macrovoid=1; + ret=RasmAssembleInfoParam(AUTOTEST_PARAM_VOID,strlen(AUTOTEST_PARAM_VOID),&opcode,&opcodelen,&debug,¶m); + if (ret) {} else {printf("Autotest %03d ERROR (testing compilation option -void)\n",cpt);MiniDump(opcode,opcodelen);for (i=0;inberror;i++) printf("%d -> %s\n",i,debug->error[i].msg);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; + RasmFreeInfoStruct(debug); +printf("testing command line parameter -void OK\n"); + + #define AUTOTEST_PARAM_VOID2 "macro grouik : nop : mend : grouik (void)" + memset(¶m,0,sizeof(struct s_parameter)); + param.macrovoid=1; + ret=RasmAssembleInfoParam(AUTOTEST_PARAM_VOID2,strlen(AUTOTEST_PARAM_VOID2),&opcode,&opcodelen,&debug,¶m); + if (!ret) {} else {printf("Autotest %03d ERROR (testing compilation option (bis) -void)\n",cpt);MiniDump(opcode,opcodelen);for (i=0;inberror;i++) printf("%d -> %s\n",i,debug->error[i].msg);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; + RasmFreeInfoStruct(debug); +printf("testing command line parameter (bis) -void OK\n"); + + #define AUTOTEST_PARAM_TWE "ld a,300" + memset(¶m,0,sizeof(struct s_parameter)); + param.erronwarn=1; + ret=RasmAssembleInfoParam(AUTOTEST_PARAM_TWE,strlen(AUTOTEST_PARAM_TWE),&opcode,&opcodelen,&debug,¶m); + if (ret) {} else {printf("Autotest %03d ERROR (testing compilation option -twe)\n",cpt);MiniDump(opcode,opcodelen);for (i=0;inberror;i++) printf("%d -> %s\n",i,debug->error[i].msg);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; + RasmFreeInfoStruct(debug); +printf("testing command line parameter -twe OK\n"); + +/* + #define AUTOTEST_PARAM_ "" + memset(¶m,0,sizeof(struct s_parameter)); + param.dams=1; + ret=RasmAssembleInfoParam(AUTOTEST_PARAM_,strlen(AUTOTEST_PARAM_),&opcode,&opcodelen,&debug,¶m); + if (!ret) {} else {printf("Autotest %03d ERROR (testing compilation option -)\n",cpt);MiniDump(opcode,opcodelen);for (i=0;inberror;i++) printf("%d -> %s\n",i,debug->error[i].msg);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; + RasmFreeInfoStruct(debug); +printf("testing command line parameter - OK\n"); + + #define AUTOTEST_PARAM_ "" + memset(¶m,0,sizeof(struct s_parameter)); + param.dams=1; + ret=RasmAssembleInfoParam(AUTOTEST_PARAM_,strlen(AUTOTEST_PARAM_),&opcode,&opcodelen,&debug,¶m); + if (!ret) {} else {printf("Autotest %03d ERROR (testing compilation option -)\n",cpt);MiniDump(opcode,opcodelen);for (i=0;inberror;i++) printf("%d -> %s\n",i,debug->error[i].msg);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; + RasmFreeInfoStruct(debug); +printf("testing command line parameter - OK\n"); +*/ + + + + /* Autotest single instruction writes that must failed */ + tmpstr3=TxtStrDup(AUTOTEST_INSTRMUSTFAILED); + tmpsplit=TxtSplitWithChar(tmpstr3,':'); + + for (i=0;tmpsplit[i];i++) { + ret=RasmAssemble(tmpsplit[i],strlen(tmpsplit[i]),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (opcodes that must fail) -> [%s]\n",cpt,tmpsplit[i]);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL; + } + + MemFree(tmpstr3);FreeFields(tmpsplit); + cpt++; +printf("testing various opcode tests OK\n"); + + idx=0; + while (autotest_keyword[idx].keywordtest) { + ret=RasmAssemble(autotest_keyword[idx].keywordtest,strlen(autotest_keyword[idx].keywordtest),&opcode,&opcodelen); + if (!ret && !autotest_keyword[idx].result) { + } else if (ret && autotest_keyword[idx].result) { + } else { + printf("Autotest %03d ERROR ([%s] test) has %d error%s instead of %serror expected\n",cpt,autotest_keyword[idx].keywordtest,ret,ret>1?"s":"",autotest_keyword[idx].result?"":"no "); + sko++; + } + if (opcode) MemFree(opcode);opcode=NULL; + idx++; + } + cpt++; +printf("testing moar various opcode tests OK\n"); + + { + unsigned char RAMEMU[65536*2]; + + for (i=0;i<65536*2;i++) RAMEMU[i]=0xDD; + ret=RasmAssembleInfoIntoRAM(AUTOTEST_INTORAM1,strlen(AUTOTEST_INTORAM1),&debug, RAMEMU,65536*2); + if (ret || RAMEMU[0]!=0xDD || RAMEMU[0x8000]!=0xDD || RAMEMU[0xC000]!=0xDD || memcmp(&RAMEMU[0x3FF8],"roudoudou",9)) {printf("Autotest %03d ERROR (Assemble into emulator RAM)\n",cpt); + RAMEMU[0x4020]=0; + printf("ret=%d R[0]=%02X R[0xC000]=%02X str=[%s]\n ",ret,RAMEMU[0],RAMEMU[0xC000],&RAMEMU[0x3FF8]); + + exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; + RasmFreeInfoStruct(debug); +printf("testing assembling into external RAM OK\n"); + } + + ret=RasmAssemble(AUTOTEST_ORG,strlen(AUTOTEST_ORG),&opcode,&opcodelen); + if (!ret && opcodelen==4 && opcode[1]==0x80 && opcode[2]==2 && opcode[3]==0x10) {} else {printf("Autotest %03d ERROR (ORG relocation)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing ORG relocation OK\n"); + + ret=RasmAssemble(AUTOTEST_MAXERROR,strlen(AUTOTEST_MAXERROR),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (must return an error code!)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing error code OK\n"); + + ret=RasmAssemble(AUTOTEST_BANKORG,strlen(AUTOTEST_BANKORG),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (BANK org adr)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing BANK/ORG OK\n"); + + ret=RasmAssemble(AUTOTEST_LIMITOK,strlen(AUTOTEST_LIMITOK),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (limit ok)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing LIMIT 1 OK\n"); + + ret=RasmAssemble(AUTOTEST_LIMITKO,strlen(AUTOTEST_LIMITKO),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (out of limit)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing LIMIT 2 OK\n"); + + ret=RasmAssemble(AUTOTEST_LIMIT03,strlen(AUTOTEST_LIMIT03),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (limit: negative limit)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing inegative LIMIT OK\n"); + + ret=RasmAssemble(AUTOTEST_LIMIT04,strlen(AUTOTEST_LIMIT04),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (limit: max limit test)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing max LIMIT OK\n"); + + ret=RasmAssemble(AUTOTEST_LIMIT05,strlen(AUTOTEST_LIMIT05),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (limit: ldir in #FFFF)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing 16 bits opcode overriding LIMIT OK\n"); + + ret=RasmAssemble(AUTOTEST_LIMIT06,strlen(AUTOTEST_LIMIT06),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (limit: nop in #FFFF)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing opcode overriding LIMIT OK\n"); + + ret=RasmAssemble(AUTOTEST_LIMIT07,strlen(AUTOTEST_LIMIT07),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (limit: ld hl,#1234 in #FFFF)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing opcode with variable overriding LIMIT OK\n"); + + ret=RasmAssemble(AUTOTEST_ALIGN,strlen(AUTOTEST_ALIGN),&opcode,&opcodelen); + if (!ret && opcodelen==257 && opcode[64]==64 && opcode[128]==128 && opcode[256]==255) {} else {printf("Autotest %03d ERROR (ALIGN directive)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing ALIGN OK\n"); + + ret=RasmAssemble(AUTOTEST_CONFINE,strlen(AUTOTEST_CONFINE),&opcode,&opcodelen); + if (!ret && opcodelen==501 && opcode[256]==0xAA && opcode[500]==0xBB) {} else {printf("Autotest %03d ERROR (HICONFINE directive)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing CONFINE OK\n"); + + ret=RasmAssemble(AUTOTEST_DELAYED_RUN,strlen(AUTOTEST_DELAYED_RUN),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (delayed RUN set)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing delayed RUN OK\n"); + + ret=RasmAssemble(AUTOTEST_LZSEGMENT,strlen(AUTOTEST_LZSEGMENT),&opcode,&opcodelen); + if (!ret && opcodelen==23 && opcode[1]==21 && opcode[9]==23) {} else {printf("Autotest %03d ERROR (LZ segment relocation)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing LZ segment relocation OK\n"); + +#ifndef NOAPULTRA +#ifndef NO_3RD_PARTIES + ret=RasmAssemble(AUTOTEST_MULTILZ,strlen(AUTOTEST_MULTILZ),&opcode,&opcodelen); + if (!ret && opcodelen==43 && opcode[3]==6 && opcode[11]==0x1F) {} else {printf("Autotest %03d ERROR (multi-LZ segment relocation with multiple BANK)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing multi-LZ segment relocation with multiple banks OK\n"); +#else +printf("*** multi-LZ segment test disabled as there is no APUltra support for this version ***\n"); +#endif +#else +printf("*** multi-LZ segment test disabled as there is no APUltra support for this version ***\n"); +#endif + ret=RasmAssemble(AUTOTEST_MULTILZORG,strlen(AUTOTEST_MULTILZORG),&opcode,&opcodelen); + if (!ret && opcodelen==38 && opcode[0]==6 && opcode[2]==0x10 + && opcode[4]==0x1A && opcode[0x23]==0xFF && opcode[0x24]==0xFB) {} else {printf("Autotest %03d ERROR (LZ segments mixed with ORG)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing LZ segment + ORG relocation OK\n"); + + + ret=RasmAssemble(AUTOTEST_LZDEFERED,strlen(AUTOTEST_LZDEFERED),&opcode,&opcodelen); + if (!ret && opcodelen==7 && opcode[6]==6) {} else {printf("Autotest %03d ERROR (LZ segment + defered $)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing LZ segment + defered $ OK\n"); + +#ifndef NO_3RD_PARTIES + ret=RasmAssemble(AUTOTEST_LZ4,strlen(AUTOTEST_LZ4),&opcode,&opcodelen); + if (!ret && opcodelen==49 && opcode[0]==0x15 && opcode[4]==0x44 && opcode[0xB]==0xF0) {} else {printf("Autotest %03d ERROR (LZ4 segment)\n",cpt);MiniDump(opcode,opcodelen);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing LZ4 segment OK\n"); +#endif + ret=RasmAssemble(AUTOTEST_DEFS,strlen(AUTOTEST_DEFS),&opcode,&opcodelen); + if (!ret && opcodelen==256 && opcode[0]==0) {} else {printf("Autotest %03d ERROR (defs)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing DEFS OK\n"); + + ret=RasmAssemble(AUTOTEST_BANKSET,strlen(AUTOTEST_BANKSET),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (bank/bankset)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing BANK/BANKSET OK\n"); + + ret=RasmAssemble(AUTOTEST_PAGETAG,strlen(AUTOTEST_PAGETAG),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (page/pageset)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing prefix PAGE/PAGESET 1 OK\n"); + + ret=RasmAssemble(AUTOTEST_PAGETAG2,strlen(AUTOTEST_PAGETAG2),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (page/pageset 2)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing prefix PAGE/PAGESET 2 OK\n"); + + ret=RasmAssemble(AUTOTEST_PAGETAG3,strlen(AUTOTEST_PAGETAG3),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (page/pageset 3)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing prefix PAGE/PAGESET 3 OK\n"); + + ret=RasmAssemble(AUTOTEST_UNDEF,strlen(AUTOTEST_UNDEF),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (simple undef)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing UNDEF OK\n"); + + ret=RasmAssemble(AUTOTEST_TAGPRINT,strlen(AUTOTEST_TAGPRINT),&opcode,&opcodelen); + if (!ret && opcodelen==1 && opcode[0]==0xC9) {} else {printf("Autotest %03d ERROR (tag inside printed string)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing tags inside printed string OK\n"); + + ret=RasmAssemble(AUTOTEST_TAGFOLLOW,strlen(AUTOTEST_TAGFOLLOW),&opcode,&opcodelen); + if (!ret && opcodelen==1 && opcode[0]==0xC9) {} else {printf("Autotest %03d ERROR (tag+alias fast translating)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing tag+alias in fast translate OK\n"); + + ret=RasmAssemble(AUTOTEST_TAGREALLOC,strlen(AUTOTEST_TAGREALLOC),&opcode,&opcodelen); + if (!ret && opcodelen==276) {} else {printf("Autotest %03d ERROR (tag realloc with fast translate)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing tag realloc with fast translate OK\n"); + + ret=RasmAssemble(AUTOTEST_TAGLOOP,strlen(AUTOTEST_TAGLOOP),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (generated alias inside loop with generated var names )\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing generated alias inside loop with generated var names OK\n"); + + ret=RasmAssemble(AUTOTEST_PRINTVAR,strlen(AUTOTEST_PRINTVAR),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (param inside printed string)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing param inside printed string OK\n"); + + ret=RasmAssemble(AUTOTEST_PRINTSPACE,strlen(AUTOTEST_PRINTSPACE),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (space inside tag string for PRINT directive)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing space inside tag string for PRINT directive OK\n"); + + ret=RasmAssemble(AUTOTEST_INHIBITION,strlen(AUTOTEST_INHIBITION),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (conditionnal inhibition)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing conditionnal inhibition OK\n"); + + ret=RasmAssemble(AUTOTEST_SWITCH,strlen(AUTOTEST_SWITCH),&opcode,&opcodelen); + if (!ret && opcodelen==3 && opcode[0]==4 && opcode[1]==3 && opcode[2]==4) {} else {printf("Autotest %03d ERROR (switch case)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing SWITCH/CASE OK\n"); + + ret=RasmAssemble(AUTOTEST_NOCODE,strlen(AUTOTEST_NOCODE),&opcode,&opcodelen); + if (!ret && opcodelen==57) {} else {printf("Autotest %03d ERROR (code/nocode)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing code/nocode OK\n"); + + ret=RasmAssemble(AUTOTEST_VAREQU,strlen(AUTOTEST_VAREQU),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (var & equ)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing var & equ OK\n"); + + ret=RasmAssemble(AUTOTEST_CHARSET,strlen(AUTOTEST_CHARSET),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (simple charset)\n",cpt);exit(-1);} + if (opcodelen!=30 || memcmp(opcode,opcode+5,5) || memcmp(opcode+10,opcode+5,5)) {printf("Autotest %03d ERROR (simple charset)\n",cpt);exit(-1);} + if (memcmp(opcode+15,opcode+20,5) || memcmp(opcode+15,opcode+25,5)) {printf("Autotest %03d ERROR (simple charset)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing simple charset OK\n"); + + ret=RasmAssemble(AUTOTEST_CHARSET2,strlen(AUTOTEST_CHARSET2),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (extended charset)\n",cpt);exit(-1);} + for (i=chk=0;inberror;i++) printf("%d -> %s\n",i,debug->error[i].msg);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; + RasmFreeInfoStruct(debug); +printf("testing BANK tag + proximity labels OK\n"); + + ret=RasmAssemble(AUTOTEST_STRUCT,strlen(AUTOTEST_STRUCT),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (structs)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing structs OK\n"); + + ret=RasmAssemble(AUTOTEST_STRUCT2,strlen(AUTOTEST_STRUCT2),&opcode,&opcodelen); + if (!ret && opcodelen==1) {} else {printf("Autotest %03d ERROR (sizeof struct fields)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing SIZEOF struct fields OK\n"); + + ret=RasmAssemble(AUTOTEST_REPEAT,strlen(AUTOTEST_REPEAT),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (extended repeat)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing REPEAT cases OK\n"); + + ret=RasmAssemble(AUTOTEST_REPEAT3,strlen(AUTOTEST_REPEAT3),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (repeat options + startingindex)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing REPEAT+STARTINGINDEX cases OK\n"); + + ret=RasmAssemble(AUTOTEST_REPEATKO,strlen(AUTOTEST_REPEATKO),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (repeat without end must return error)\n",cpt);exit(-1);} +printf("testing REPEAT without REND OK\n"); + + ret=RasmAssemble(AUTOTEST_WHILEKO,strlen(AUTOTEST_WHILEKO),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (while without end must return error)\n",cpt);exit(-1);} +printf("testing WHILE without WEND OK\n"); + + ret=RasmAssemble(AUTOTEST_TICKER,strlen(AUTOTEST_TICKER),&opcode,&opcodelen); + if (!ret && opcodelen==18) {} else {printf("Autotest %03d ERROR (ticker (re)count)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing ticker OK\n"); + + ret=RasmAssemble(AUTOTEST_DEFUSED,strlen(AUTOTEST_DEFUSED),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (ifdef ifused)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing IFDEF / IFUSED OK\n"); + + ret=RasmAssemble(AUTOTEST_SAVEINVALID0,strlen(AUTOTEST_SAVEINVALID0),&opcode,&opcodelen); + if (!ret && FileGetSize("rasmoutput.bin")==256) { } else {printf("Autotest %03d ERROR (invalid file size on DISK with SAVE => mostly a pure windows compilation error)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing correct file size on DISK with SAVE OK\n"); + + ret=RasmAssemble(AUTOTEST_SAVEINVALID1,strlen(AUTOTEST_SAVEINVALID1),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (invalid size for SAVE)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing invalid size for SAVE OK\n"); + + ret=RasmAssemble(AUTOTEST_SAVEINVALID2,strlen(AUTOTEST_SAVEINVALID2),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (invalid offset for SAVE)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing invalid offset (too low) for SAVE OK\n"); + + ret=RasmAssemble(AUTOTEST_SAVEINVALID3,strlen(AUTOTEST_SAVEINVALID3),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (invalid offset for SAVE)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing invalid offset (too high) for SAVE OK\n"); + + ret=RasmAssemble(AUTOTEST_INHIBITION2,strlen(AUTOTEST_INHIBITION2),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (if switch inhibition)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing if/switch inhibition OK\n"); + + ret=RasmAssemble(AUTOTEST_INHIBITIONMAX,strlen(AUTOTEST_INHIBITIONMAX),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (moar inhibition)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing more inhibition cases OK\n"); + + ret=RasmAssemble(AUTOTEST_MACROPROX,strlen(AUTOTEST_MACROPROX),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (macro + prox)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing regression case with proximity label following macro definition OK\n"); + + ret=RasmAssemble(AUTOTEST_PROXBACK,strlen(AUTOTEST_PROXBACK),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (boucle/macro + prox = recup global)\n",cpt);MiniDump(opcode,opcodelen);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing global label back as reference when leaving macro and loops OK\n"); + + ret=RasmAssemble(AUTOTEST_LOCAPROX,strlen(AUTOTEST_LOCAPROX),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (far local+prox access)\n",cpt);MiniDump(opcode,opcodelen);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing far access of a proximity label refering to local OK\n"); + + ret=RasmAssemble(AUTOTEST_PUSHPOPGLOBAL,strlen(AUTOTEST_PUSHPOPGLOBAL),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (get back global for proximity inside macro+loops)\n",cpt);MiniDump(opcode,opcodelen);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing push/pop global label for proximity inside macro+loops OK\n"); + + ret=RasmAssemble(AUTOTEST_NEGATIVE,strlen(AUTOTEST_NEGATIVE),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (formula case 0)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing formula case 0 OK\n"); + + ret=RasmAssemble(AUTOTEST_OPERATORASSIGN,strlen(AUTOTEST_OPERATORASSIGN),&opcode,&opcodelen); + if (!ret && opcodelen==1) {} else {printf("Autotest %03d ERROR (operator assignment)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing operator assignment OK\n"); + + ret=RasmAssemble(AUTOTEST_OPERATORASSIGN2,strlen(AUTOTEST_OPERATORASSIGN2),&opcode,&opcodelen); + if (!ret && opcodelen==1) {} else {printf("Autotest %03d ERROR (operator assignment + repeat)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing operator assignment + repeat OK\n"); + + ret=RasmAssemble(AUTOTEST_OPERATORASSIGN3,strlen(AUTOTEST_OPERATORASSIGN3),&opcode,&opcodelen); + if (!ret && opcodelen==1) {} else {printf("Autotest %03d ERROR (operator assignment + repeat)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing operator assignment + repeat + spacing OK\n"); + + ret=RasmAssemble(AUTOTEST_REAL,strlen(AUTOTEST_REAL),&opcode,&opcodelen); + if (!ret && opcodelen==sizeof(RealDump) && memcmp(RealDump,opcode,sizeof(RealDump))==0) {} else {printf("Autotest %03d ERROR (DEFR conversion to REAL)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing Amstrad REAL OK\n"); + + ret=RasmAssemble(AUTOTEST_FORMULA1,strlen(AUTOTEST_FORMULA1),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (formula case 1)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing formula case 1 OK\n"); + + ret=RasmAssemble(AUTOTEST_SETINSIDE,strlen(AUTOTEST_SETINSIDE),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (set var inside expression must trigger error)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing var set inside an expression must trigger an error OK\n"); + + ret=RasmAssemble(AUTOTEST_CODESKIP,strlen(AUTOTEST_CODESKIP),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (code skip)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing code skip OK\n"); + + ret=RasmAssemble(AUTOTEST_FORMULA2,strlen(AUTOTEST_FORMULA2),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (formula case 2 function+multiple parenthesis)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing formula functions + multiple parenthesis OK\n"); + + ret=RasmAssembleInfo(AUTOTEST_GETSIZE,strlen(AUTOTEST_GETSIZE),&opcode,&opcodelen,&debug); + if (!ret) {} else {printf("Autotest %03d ERROR (math function GETSIZE)\n",cpt);for (i=0;inberror;i++) printf("%d -> %s\n",i,debug->error[i].msg);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; + RasmFreeInfoStruct(debug); +printf("testing GETSIZE integrity on ALL opcodes OK\n"); + + ret=RasmAssemble(AUTOTEST_GETNOP_LD,strlen(AUTOTEST_GETNOP_LD),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (math function GETNOP with multiple LD syncronised with TICKER)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing synchronisation between TICKER and GETNOP on multiple LD OK\n"); + + ret=RasmAssemble(AUTOTEST_TICKERNOP_FULL,strlen(AUTOTEST_TICKERNOP_FULL),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (math function GETNOP with almost full instruction set)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing synchronisation between TICKER and GETNOP on almost full instruction set OK\n"); + + ret=RasmAssemble(AUTOTEST_TICKER_FULL,strlen(AUTOTEST_TICKER_FULL),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (math function GETTICK with almost full instruction set)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing synchronisation between TICKER and GETTICK on almost full instruction set OK\n"); + + ret=RasmAssemble(AUTOTEST_SHIFTMAX,strlen(AUTOTEST_SHIFTMAX),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (shifting more than 31 must give zero result)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing shifting more than 31 OK\n"); + + ret=RasmAssemble(AUTOTEST_PLUSCOLOR,strlen(AUTOTEST_PLUSCOLOR),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (formula func for Plus color management)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing formula function for Plus color management OK\n"); + + ret=RasmAssemble(AUTOTEST_FRAC,strlen(AUTOTEST_FRAC),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (formula func FRAC)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing formula FRAC function OK\n"); + + ret=RasmAssemble(AUTOTEST_RND,strlen(AUTOTEST_RND),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (formula func RND)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing formula RND function OK\n"); + + ret=RasmAssemble(AUTOTEST_UNDERVAR,strlen(AUTOTEST_UNDERVAR),&opcode,&opcodelen); + if (!ret && opcodelen==4) {} else {printf("Autotest %03d ERROR (var starting with _)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing var names starting with '_' OK\n"); + + ret=RasmAssemble(AUTOTEST_NOEXPORT,strlen(AUTOTEST_NOEXPORT),&opcode,&opcodelen); + if (!ret && opcodelen==2) {} else {printf("Autotest %03d ERROR (noexport/enoexport)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing export/noexport OK\n"); + + ret=RasmAssemble(AUTOTEST_ENHANCED_LD,strlen(AUTOTEST_ENHANCED_LD),&opcode,&opcodelen); + if (!ret && memcmp(opcode,opcode+opcodelen/2,opcodelen/2)==0) {} else {printf("Autotest %03d ERROR (enhanced LD)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing enhanced LD OK\n"); + + ret=RasmAssemble(AUTOTEST_ENHANCED_LD2,strlen(AUTOTEST_ENHANCED_LD2),&opcode,&opcodelen); + if (!ret && memcmp(opcode,opcode+opcodelen/2,opcodelen/2)==0) {} else {printf("Autotest %03d ERROR (enhanced LD 2)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing enhanced LD variante OK\n"); + + ret=RasmAssemble(AUTOTEST_ENHANCED_LD3,strlen(AUTOTEST_ENHANCED_LD3),&opcode,&opcodelen); + if (!ret && memcmp(opcode,opcode+opcodelen/2,opcodelen/2)==0) {} else {printf("Autotest %03d ERROR (enhanced LD 3)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing enhanced LD variante OK\n"); + + ret=RasmAssemble(AUTOTEST_ENHANCED_PUSHPOP,strlen(AUTOTEST_ENHANCED_PUSHPOP),&opcode,&opcodelen); + if (!ret && memcmp(opcode,opcode+opcodelen/2,opcodelen/2)==0) {} else {printf("Autotest %03d ERROR (enhanced PUSH/POP/NOP)\n",cpt);MiniDump(opcode,opcodelen);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing enhanced PUSH/POP OK\n"); + + ret=RasmAssembleInfo(AUTOTEST_INKCONV,strlen(AUTOTEST_INKCONV),&opcode,&opcodelen,&debug); + if (!ret && opcodelen==2) {} else {printf("Autotest %03d ERROR (gate array color conversion)\n",cpt);MiniDump(opcode,opcodelen);for (i=0;inberror;i++) printf("%d -> %s\n",i,debug->error[i].msg);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; + RasmFreeInfoStruct(debug); +printf("testing gate array color conversion OK\n"); + + FileRemoveIfExists("autotest_include.raw"); + opcode=MemMalloc(256); + for (i=0;i<256;i++) opcode[i]=i; + FileWriteBinary("autotest_include.raw",(char *)opcode,256); + FileWriteBinaryClose("autotest_include.raw"); + MemFree(opcode);opcode=NULL; + + ret=RasmAssembleInfo(AUTOTEST_GTILES,strlen(AUTOTEST_GTILES),&opcode,&opcodelen,&debug); + if (!ret && opcodelen==256 && opcode[0]==0 && opcode[3]==3 && opcode[4]==4 && opcode[8]==12 && opcode[12]==8 && opcode[16]==24 && opcode[20]==28 && opcode[24]==20 && opcode[28]==16) {} // minimal check + else {printf("Autotest %03d ERROR (INCBIN GTILES import)\n",cpt);MiniDump(opcode,opcodelen);for (i=0;inberror;i++) printf("%d -> %s\n",i,debug->error[i].msg);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; + RasmFreeInfoStruct(debug); +printf("testing gray coding tile import OK\n"); + + ret=RasmAssembleInfo(AUTOTEST_ITILES,strlen(AUTOTEST_ITILES),&opcode,&opcodelen,&debug); + if (!ret && opcodelen==256 && opcode[0]==0 && opcode[3]==3 && opcode[4]==7 && opcode[8]==12 && opcode[12]==11 && opcode[16]==24 && opcode[20]==31 && opcode[24]==20 && opcode[28]==19) {} // minimal check + else {printf("Autotest %03d ERROR (INCBIN ITILES import)\n",cpt);MiniDump(opcode,opcodelen);for (i=0;inberror;i++) printf("%d -> %s\n",i,debug->error[i].msg);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; + RasmFreeInfoStruct(debug); +printf("testing zigzag gray coding tile import OK\n"); + + ret=RasmAssembleInfo(AUTOTEST_GTILES_KO,strlen(AUTOTEST_GTILES_KO),&opcode,&opcodelen,&debug); + if (ret) {} // must be error + else {printf("Autotest %03d ERROR (INCBIN GTILES import check)\n",cpt);MiniDump(opcode,opcodelen);for (i=0;inberror;i++) printf("%d -> %s\n",i,debug->error[i].msg);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; + RasmFreeInfoStruct(debug); +printf("testing gray coding tile size check error OK\n"); + + ret=RasmAssembleInfo(AUTOTEST_ITILES_KO,strlen(AUTOTEST_ITILES_KO),&opcode,&opcodelen,&debug); + if (ret) {} // must be error + else {printf("Autotest %03d ERROR (INCBIN ITILES import check)\n",cpt);MiniDump(opcode,opcodelen);for (i=0;inberror;i++) printf("%d -> %s\n",i,debug->error[i].msg);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; + RasmFreeInfoStruct(debug); +printf("testing zigzag gray coding tile size check error OK\n"); + + +/************************** segfault test **********************/ + ret=RasmAssembleInfo(AUTOTEST_ACCENT,strlen(AUTOTEST_ACCENT),&opcode,&opcodelen,&debug); + if (opcode) MemFree(opcode);opcode=NULL;cpt++; + RasmFreeInfoStruct(debug); +printf("testing segfault bugfix for accent in quote OK\n"); + ret=RasmAssembleInfo(AUTOTEST_QUOTELAST,strlen(AUTOTEST_QUOTELAST),&opcode,&opcodelen,&debug); + if (opcode) MemFree(opcode);opcode=NULL;cpt++; + RasmFreeInfoStruct(debug); +printf("testing segfault bugfix for opened quote with SAVE as last directive used OK\n"); + ret=RasmAssembleInfo(AUTOTEST_DELAYED_EQU,strlen(AUTOTEST_DELAYED_EQU),&opcode,&opcodelen,&debug); + if (!ret && opcodelen>2 && opcode[2]==1) {} else {printf("Autotest %03d ERROR (DELAYED EQU regression test)\n",cpt);MiniDump(opcode,opcodelen);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; + RasmFreeInfoStruct(debug); +printf("testing delayed alias regression bugfix OK\n"); + +/*************************************************************/ + + + ret=RasmAssembleInfo(AUTOTEST_SNASET,strlen(AUTOTEST_SNASET),&opcode,&opcodelen,&debug); + if (!ret) {} else {printf("Autotest %03d ERROR (snapshot settings)\n",cpt);MiniDump(opcode,opcodelen);for (i=0;inberror;i++) printf("%d -> %s\n",i,debug->error[i].msg);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; + RasmFreeInfoStruct(debug); +printf("testing snapshot settings OK\n"); + + ret=RasmAssemble(AUTOTEST_PAGELABELGEN,strlen(AUTOTEST_PAGELABELGEN),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (pagelabelgen)\n",cpt);MiniDump(opcode,opcodelen);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing page tag with generated label name OK\n"); + + ret=RasmAssembleInfo(AUTOTEST_EMBEDDED_ERRORS,strlen(AUTOTEST_EMBEDDED_ERRORS),&opcode,&opcodelen,&debug); + if (ret && debug->nberror==2 && debug->nbsymbol==3) { +/* + printf("\n"); + for (i=0;inberror;i++) { + printf("%d -> %s\n",i,debug->error[i].msg); + } + for (i=0;inbsymbol;i++) { + printf("%d -> %s=%d\n",i,debug->symbol[i].name,debug->symbol[i].v); + } +*/ + RasmFreeInfoStruct(debug); + } else {printf("Autotest %03d ERROR (embedded error struct) err=%d nberr=%d (2) nbsymb=%d (3)\n",cpt,ret,debug->nberror,debug->nbsymbol);MiniDump(opcode,opcodelen);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing internal error struct OK\n"); + + ret=RasmAssembleInfo(AUTOTEST_EMBEDDED_LABELS,strlen(AUTOTEST_EMBEDDED_LABELS),&opcode,&opcodelen,&debug); + if (!ret && debug->nbsymbol==3) { + /* + printf("\nnbsymbol=%d\n",debug->nbsymbol); + for (i=0;inbsymbol;i++) { + printf("%d -> %s=%d\n",i,debug->symbol[i].name,debug->symbol[i].v); + }*/ + RasmFreeInfoStruct(debug); + } else {printf("Autotest %03d ERROR (embedded test)\n",cpt);MiniDump(opcode,opcodelen);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing internal label struct OK\n"); + +#ifdef RDD + printf("\n%d bytes\n",_static_library_memory_used); + { + int filelen; + tmpstr3=FileReadContent("./test/PlayerAky.asm",&filelen); + printf(".");fflush(stdout);ret=RasmAssembleInfo(tmpstr3,filelen,&opcode,&opcodelen,&debug); + if (!ret) {} else {printf("Autotest %03d ERROR (PlayerAky)\n",cpt);MiniDump(opcode,opcodelen);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; + RasmFreeInfoStruct(debug); + MemFree(tmpstr3); + } + + printf("\n%d bytes\n",_static_library_memory_used); +#endif + + /************************** include testing + crunch ****************/ + idx=0; + opcode=MemMalloc(8000); + for (k=40;k>1;k--) { + for (i='A';i<'F';i++) { + for (j=0;j various opcode tests did not pass! (check backlog)\n"); + printf("All other tests OK => %d tests done\n",ret); + } else { + printf("All internal tests OK => %d tests done\n",ret); + } + + + #ifdef RDD + /* private dev lib tools */ +printf("checking memory\n"); + CloseLibrary(); + #endif + exit(0); +} + + +/****************************************************** +LZ48 v005 / LZ49 v002 +******************************************************/ +int LZ48_encode_extended_length(unsigned char *odata, int length) +{ + int ioutput=0; + + while (length>=255) { + odata[ioutput++]=0xFF; + length-=255; + } + /* if the last value is 255 we must encode 0 to end extended length */ + /*if (length==0) rasm_printf(ae,"bugfixed!\n");*/ + odata[ioutput++]=(unsigned char)length; + return ioutput; +} + +int LZ48_encode_block(unsigned char *odata,unsigned char *data, int literaloffset,int literalcpt,int offset,int maxlength) +{ + int ioutput=1; + int token=0; + int i; + + if (offset<0 || offset>255) { + fprintf(stderr,"internal offset error!\n"); + exit(-2); + } + + if (literalcpt<15) { + token=literalcpt<<4; + } else { + token=0xF0; + ioutput+=LZ48_encode_extended_length(odata+ioutput,literalcpt-15); + } + + for (i=0;i2) { + token|=(maxlength-3); + } else { + /* endoffset has no length */ + } + } else { + token|=0xF; + ioutput+=LZ48_encode_extended_length(odata+ioutput,maxlength-18); + } + + odata[ioutput++]=(unsigned char)offset-1; + + odata[0]=(unsigned char)token; + return ioutput; +} + +unsigned char *LZ48_encode_legacy(unsigned char *data, int length, int *retlength) +{ + int i,startscan,current=1,token,ioutput=1,curscan; + int maxoffset=0,maxlength,matchlength,literal=0,literaloffset=1; + unsigned char *odata=NULL; + + odata=MemMalloc((size_t)length*1.5+10); + if (!odata) { + fprintf(stderr,"malloc(%.0lf) - memory full\n",(size_t)length*1.5+10); + exit(-1); + } + + /* first byte always literal */ + odata[0]=data[0]; + + /* force short data encoding */ + if (length<5) { + token=(length-1)<<4; + odata[ioutput++]=(unsigned char)token; + for (i=1;i=3 && matchlength>maxlength) { + maxoffset=startscan; + maxlength=matchlength; + } + startscan++; + } + if (maxlength) { + ioutput+=LZ48_encode_block(odata+ioutput,data,literaloffset,literal,current-maxoffset,maxlength); + current+=maxlength; + literaloffset=current; + literal=0; + } else { + literal++; + current++; + } + } + ioutput+=LZ48_encode_block(odata+ioutput,data,literaloffset,literal,0,0); + *retlength=ioutput; + return odata; +} + +int LZ49_encode_extended_length(unsigned char *odata, int length) +{ + int ioutput=0; + + while (length>=255) { + odata[ioutput++]=0xFF; + length-=255; + } + /* if the last value is 255 we must encode 0 to end extended length */ + /*if (length==0) rasm_printf(ae,"bugfixed!\n");*/ + odata[ioutput++]=(unsigned char)length; + return ioutput; +} + +int LZ49_encode_block(unsigned char *odata,unsigned char *data, int literaloffset,int literalcpt,int offset,int maxlength) +{ + int ioutput=1; + int token=0; + int i; + + if (offset<0 || offset>511) { + fprintf(stderr,"internal offset error!\n"); + exit(-2); + } + + if (literalcpt<7) { + token=literalcpt<<4; + } else { + token=0x70; + ioutput+=LZ49_encode_extended_length(odata+ioutput,literalcpt-7); + } + + for (i=0;i2) { + token|=(maxlength-3); + } else { + /* endoffset has no length */ + } + } else { + token|=0xF; + ioutput+=LZ49_encode_extended_length(odata+ioutput,maxlength-18); + } + + if (offset>255) { + token|=0x80; + offset-=256; + } + odata[ioutput++]=(unsigned char)offset-1; + + odata[0]=(unsigned char)token; + return ioutput; +} + +unsigned char *LZ49_encode_legacy(unsigned char *data, int length, int *retlength) +{ + int i,startscan,current=1,token,ioutput=1,curscan; + int maxoffset=0,maxlength,matchlength,literal=0,literaloffset=1; + unsigned char *odata=NULL; + + odata=MemMalloc((size_t)(length*1.5+10)); + if (!odata) { + fprintf(stderr,"malloc(%.0lf) - memory full\n",(size_t)length*1.5+10); + exit(-1); + } + + /* first byte always literal */ + odata[0]=data[0]; + + /* force short data encoding */ + if (length<5) { + token=(length-1)<<4; + odata[ioutput++]=(unsigned char)token; + for (i=1;i=3 && matchlength>maxlength) { + maxoffset=startscan; + maxlength=matchlength; + } + startscan++; + } + if (maxlength) { + ioutput+=LZ49_encode_block(odata+ioutput,data,literaloffset,literal,current-maxoffset,maxlength); + current+=maxlength; + literaloffset=current; + literal=0; + } else { + literal++; + current++; + } + } + ioutput+=LZ49_encode_block(odata+ioutput,data,literaloffset,literal,0,0); + *retlength=ioutput; + return odata; +} + + +/*************************************** + semi-generic body of program +***************************************/ + +#ifndef INTEGRATED_ASSEMBLY + +/* + Usage + display the mandatory parameters +*/ +void Usage(int help) +{ + #undef FUNC + #define FUNC "Usage" + + printf("%s (c) 2017 Edouard BERGE (use -n option to display all licenses / -autotest for self-testing)\n",RASM_VERSION); + #ifndef NO_3RD_PARTIES + printf("LZ4 (c) Yann Collet / ZX0 & ZX7 (c) Einar Saukas / Exomizer 2 (c) Magnus Lind / LZSA & AP-Ultra (c) Emmanuel Marty\n"); + #endif + printf("\n"); + printf("SYNTAX: rasm [options]\n"); + printf("\n"); + + if (help) { + printf("FILENAMES:\n"); + printf("-oa automatic radix from input filename\n"); + printf("-o choose a common radix for all files\n"); + printf("-or choose a radix filename for ROM output\n"); + printf("-ob choose a full filename for binary output\n"); + printf("-oc choose a full filename for cartridge output\n"); + printf("-ol choose a full filename for ROM label output\n"); + printf("-oi choose a full filename for snapshot output\n"); + printf("-os choose a full filename for symbol output\n"); + printf("-ot choose a full filename for tape output\n"); + printf("-ok choose a full filename for breakpoint output\n"); + printf("-I set a path for files to read\n"); + printf("-no disable all file output\n"); + printf("DEPENDENCIES EXPORT:\n"); + printf("-depend=make output dependencies on a single line\n"); + printf("-depend=list output dependencies as a list\n"); + printf("if 'binary filename' is set then it will be outputed first\n"); + printf("SYMBOLS EXPORT:\n"); + printf("-s export symbols %%s #%%X B%%d (label,adr,cprbank)\n"); + printf("-sz export symbols with ZX emulator convention\n"); + printf("-sp export symbols with Pasmo convention\n"); + printf("-sw export symbols with Winape convention\n"); + printf("-ss export symbols in the snapshot (SYMB chunk for ACE)\n"); + printf("-sc export symbols with source code convention\n"); + printf("-sm export symbol in multiple files (one per bank)\n"); + printf("-ec export labels with original case\n"); + printf("-er export ROM labels\n"); + printf("-l import symbol file (winape,pasmo,rasm)\n"); + printf("-eb export breakpoints\n"); + printf("-wu warn for unused symbols (alias, var or label)\n"); + printf("SYMBOLS ADDITIONAL OPTIONS:\n"); + printf("-sl export also local symbol\n"); + printf("-sv export also variables symbol\n"); + printf("-sq export also EQU symbol\n"); + printf("-sa export all symbols (like -sl -sv -sq option)\n"); + printf("-Dvariable=value import value for variable\n"); + printf("COMPATIBILITY:\n"); + printf("-m Maxam style calculations\n"); + printf("-dams Dams 'dot' label convention\n"); + printf("-ass AS80 behaviour mimic\n"); + printf("-uz UZ80 behaviour mimic\n"); + printf("-pasmo PASMO behaviour mimic\n"); + printf("-amper use ampersand for hex values\n"); + printf("-msep set separator for modules\n"); + printf("-utf8 convert symbols from french or spanish keyboard inside quotes\n"); + printf("-fq do not bother with special chars inside quotes\n"); + printf("MISCELLANEOUS:\n"); + printf("-quick enable fast mode for ZX0 crunching\n"); + printf("-cprquiet do not display ROM detailed informations\n"); + printf("EDSK generation/update:\n"); + printf("-eo overwrite files on disk if it already exists\n"); + printf("SNAPSHOT:\n"); + printf("-sb export breakpoints in snapshot (BRKS & BRKC chunks)\n"); + printf("-ss export symbols in the snapshot (SYMB chunk for ACE)\n"); + printf("-v2 export snapshot version 2 instead of version 3\n"); + printf("PARSING:\n"); + printf("-me set maximum number of error (0 means no limit)\n"); + printf("-twe treat warnings as errors\n"); + printf("-xr extended error display\n"); + printf("-w disable warnings\n"); + printf("-void force void usage with macro without parameter\n"); + printf("\n"); + } else { + printf("use option -h for help\n"); + printf("\n"); + } + + exit(ABORT_ERROR); +} + +void Licenses() +{ + #undef FUNC + #define FUNC "Licenses" + +printf(" ____ \n"); +printf(" | _ \\ __ _ ___ _ __ ___ \n"); +printf(" | |_) / _` / __| '_ ` _ \\ \n"); +printf(" | _ < (_| \\__ \\ | | | | |\n"); +printf(" |_| \\_\\__,_|___/_| |_| |_|\n"); +printf("\n"); +printf(" is using MIT 'expat' license\n"); +printf("\" Copyright (c) BERGE Edouard (roudoudou)\n\n"); + +printf("Permission is hereby granted, free of charge,\n"); +printf("to any person obtaining a copy of this software\n"); +printf("and associated documentation/source files of\n"); +printf("RASM, to deal in the Software without restriction,\n"); +printf("including without limitation the rights to use,\n"); +printf("copy, modify, merge, publish, distribute,\n"); +printf("sublicense, and/or sell copies of the Software,\n"); +printf("and to permit persons to whom the Software is\n"); +printf("furnished to do so, subject to the following\n"); +printf("conditions:\n"); + +printf("The above copyright notice and this permission\n"); +printf("notice shall be included in all copies or\n"); +printf("substantial portions of the Software.\n"); +printf("The Software is provided 'as is', without\n"); +printf("warranty of any kind, express or implied,\n"); +printf("including but not limited to the warranties of\n"); +printf("merchantability, fitness for a particular\n"); +printf("purpose and noninfringement. In no event shall\n"); +printf("the authors or copyright holders be liable for\n"); +printf("any claim, damages or other liability, whether\n"); +printf("in an action of contract, tort or otherwise,\n"); +printf("arising from, out of or in connection with the\n"); +printf("software or the use or other dealings in the\n"); +printf("Software. \"\n"); + +#ifndef NO_3RD_PARTIES +printf("\n\n\n\n"); +printf("******* license for LZ4 cruncher / sources were modified ***********\n\n\n\n"); + +printf("BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)\n"); + +printf("Redistribution and use in source and binary forms, with or without\n"); +printf("modification, are permitted provided that the following conditions are\n"); +printf("met:\n\n"); + +printf(" * Redistributions of source code must retain the above copyright\n"); +printf("notice, this list of conditions and the following disclaimer.\n"); +printf(" * Redistributions in binary form must reproduce the above\n"); +printf("copyright notice, this list of conditions and the following disclaimer\n"); +printf("in the documentation and/or other materials provided with the\n"); +printf("distribution.\n\n"); + +printf("THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"); +printf("'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"); +printf("LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"); +printf("A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"); +printf("OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"); +printf("SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"); +printf("LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"); +printf("DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"); +printf("THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"); +printf("(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"); +printf("OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n"); + +printf("You can contact the author at :\n"); +printf(" - LZ4 homepage : http://www.lz4.org\n"); +printf(" - LZ4 source repository : https://github.com/lz4/lz4\n"); + + +printf("\n\n\n\n"); +printf("******* license for ZX0 / ZX7 cruncher / sources were modified ***********\n\n\n\n"); +printf("BSD 3-Clause License\n"); +printf(" * (c) Copyright 2012/2021 by Einar Saukas. All rights reserved.\n"); +printf(" *\n"); +printf(" * Redistribution and use in source and binary forms, with or without\n"); +printf(" * modification, are permitted provided that the following conditions are met:\n"); +printf(" * * Redistributions of source code must retain the above copyright\n"); +printf(" * notice, this list of conditions and the following disclaimer.\n"); +printf(" * * Redistributions in binary form must reproduce the above copyright\n"); +printf(" * notice, this list of conditions and the following disclaimer in the\n"); +printf(" * documentation and/or other materials provided with the distribution.\n"); +printf(" * * The name of its author may not be used to endorse or promote products\n"); +printf(" * derived from this software without specific prior written permission.\n"); +printf(" *\n"); +printf(" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND\n"); +printf(" * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n"); +printf(" * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n"); +printf(" * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY\n"); +printf(" * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n"); +printf(" * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n"); +printf(" * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n"); +printf(" * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"); +printf(" * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n"); +printf(" * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"); + + + +printf("\n\n\n\n"); +printf("******* license for exomizer cruncher / sources were modified ***********\n\n\n\n"); + +printf(" * Copyright (c) 2005 Magnus Lind.\n"); +printf(" *\n"); +printf(" * This software is provided 'as-is', without any express or implied warranty.\n"); +printf(" * In no event will the authors be held liable for any damages arising from\n"); +printf(" * the use of this software.\n"); +printf(" *\n"); +printf(" * Permission is granted to anyone to use this software, alter it and re-\n"); +printf(" * distribute it freely for any non-commercial, non-profit purpose subject to\n"); +printf(" * the following restrictions:\n"); +printf(" *\n"); +printf(" * 1. The origin of this software must not be misrepresented; you must not\n"); +printf(" * claim that you wrote the original software. If you use this software in a\n"); +printf(" * product, an acknowledgment in the product documentation would be\n"); +printf(" * appreciated but is not required.\n"); +printf(" *\n"); +printf(" * 2. Altered source versions must be plainly marked as such, and must not\n"); +printf(" * be misrepresented as being the original software.\n"); +printf(" *\n"); +printf(" * 3. This notice may not be removed or altered from any distribution.\n"); +printf(" *\n"); +printf(" * 4. The names of this software and/or it's copyright holders may not be\n"); +printf(" * used to endorse or promote products derived from this software without\n"); +printf(" * specific prior written permission.\n"); + + +printf("\n\n\n\n"); +printf("******* license for AP-Ultra & LZSA crunchers ****************************\n\n\n\n"); +printf(" * apultra.c - command line compression utility for the apultra library\n"); +printf(" * Copyright (C) 2019 Emmanuel Marty\n"); +printf(" * https://github.com/emmanuel-marty\n"); +printf(" *\n"); +printf(" LZSA code use Zlib license\n"); +printf(" Match finder use CC0 license due to using portions of code from Eric Bigger's\n"); +printf(" Wimlib in the suffix array-based matchfinder\n"); +printf(" *\n"); +printf(" * This software is provided 'as-is', without any express or implied\n"); +printf(" * warranty. In no event will the authors be held liable for any damages\n"); +printf(" * arising from the use of this software.\n"); +printf(" *\n"); +printf(" * Permission is granted to anyone to use this software for any purpose,\n"); +printf(" * including commercial applications, and to alter it and redistribute it\n"); +printf(" * freely, subject to the following restrictions:\n"); +printf(" *\n"); +printf(" * 1. The origin of this software must not be misrepresented; you must not\n"); +printf(" * claim that you wrote the original software. If you use this software\n"); +printf(" * in a product, an acknowledgment in the product documentation would be\n"); +printf(" * appreciated but is not required.\n"); +printf(" * 2. Altered source versions must be plainly marked as such, and must not be\n"); +printf(" * misrepresented as being the original software.\n"); +printf(" * 3. This notice may not be removed or altered from any source distribution.\n"); +printf(" *\n"); +printf(" * Uses the libdivsufsort library Copyright (c) 2003-2008 Yuta Mori\n"); +printf(" *\n"); +printf(" * Inspired by cap by Sven-Ake Dahl. https://github.com/svendahl/cap\n"); +printf(" * Also inspired by Charles Bloom's compression blog. http://cbloomrants.blogspot.com/\n"); +printf(" * With ideas from LZ4 by Yann Collet. https://github.com/lz4/lz4\n"); +printf(" * With help and support from spke \n"); +printf("\n\n\n\n"); +printf("*** license for CDT export (record11() function and some other code extracts) ***\n\n\n\n"); +printf("Author: CNGSoft http://cngsoft.no-ip.org , the tool is in GPL2 licence,\nCopyright (C) 2007 Free Software Foundation, Inc. https://fsf.org\n"); +printf("\n"); +printf("\n"); +#endif + +printf("\n\n"); + + + + exit(0); +} + +int _internal_check_flexible(char *fxp) { + #undef FUNC + #define FUNC "_internal_check_flexible" + + char *posval,*posvar; + int cpt=0,i; + + posvar=strstr(fxp,"%s"); + posval=strstr(fxp,"%"); + if (!posval || !posvar) { + printf("invalid flexible export string, need 2 formated fields, example: \"%%s %%d\"\n"); + exit(1); + } + if (posval2) { + printf("invalid flexible export string, must be only two formated fields, example: \"%%s %%d\"\n"); + exit(1); + } + + return 1; +} +/* + ParseOptions + + used to parse command line and configuration file +*/ +int ParseOptions(char **argv,int argc, struct s_parameter *param) +{ + #undef FUNC + #define FUNC "ParseOptions" + + char *sep; + int i=0; + + if (strcmp(argv[i],"-autotest")==0) { + RasmAutotest(); + } else if (strcmp(argv[i],"-uz")==0) { + param->as80=2; + } else if (strcmp(argv[i],"-quick")==0) { + MAX_OFFSET_ZX0=2176; + } else if (strcmp(argv[i],"-msep")==0) { + if (i+1module_separator=argv[++i][0]; + } else Usage(1); + } else if (strcmp(argv[i],"-fq")==0) { + param->freequote=1; + } else if (strcmp(argv[i],"-utf8")==0) { + param->utf8enable=1; + } else if (strcmp(argv[i],"-twe")==0) { + param->erronwarn=1; + } else if (strcmp(argv[i],"-pasmo")==0) { + param->pasmo=1; + } else if (strcmp(argv[i],"-cprquiet")==0) { + param->cprinfo=0; + } else if (strcmp(argv[i],"-ass")==0) { + param->as80=1; + } else if (strcmp(argv[i],"-amper")==0 || strcmp(argv[i],"--noampersand")==0) { + param->noampersand=1; + } else if (strcmp(argv[i],"-eb")==0) { + param->export_brk=1; + } else if (strcmp(argv[i],"-wu")==0) { + param->warn_unused=1; + } else if (strcmp(argv[i],"-xpr")==0) { + param->xpr=1; + } else if (strcmp(argv[i],"-dams")==0) { + } else if (strcmp(argv[i],"-void")==0) { + param->macrovoid=1; + } else if (strcmp(argv[i],"-ec")==0) { + param->enforce_symbol_case=1; + } else if (strcmp(argv[i],"-er")==0) { + param->cprinfoexport=1; + } else if (strcmp(argv[i],"-xr")==0) { + param->extended_error=1; + } else if (strcmp(argv[i],"-eo")==0) { + param->edskoverwrite=1; + } else if (strcmp(argv[i],"-depend=make")==0) { + param->dependencies=E_DEPENDENCIES_MAKE; + param->checkmode=1; + } else if (strcmp(argv[i],"-depend=list")==0) { + param->dependencies=E_DEPENDENCIES_LIST; + param->checkmode=1; + } else if (strcmp(argv[i],"-no")==0) { + param->checkmode=1; + } else if (strcmp(argv[i],"-w")==0) { + param->nowarning=1; + } else if (argv[i][0]=='-') { + switch(argv[i][1]) + { + case 'I': + if (argv[i][2]) { + char *curpath; + int l; + l=strlen(argv[i]); + curpath=MemMalloc(l); /* strlen(path)+2 */ + strcpy(curpath,argv[i]+2); + +#ifdef OS_WIN + if (argv[i][l-1]!='/' && argv[i][l-1]!='\\') strcat(curpath,"\\"); +#else + if (argv[i][l-1]!='/' && argv[i][l-1]!='\\') strcat(curpath,"/"); +#endif + +printf("curpath=[%s]\n",curpath); + + FieldArrayAddDynamicValueConcat(¶m->pathdef,¶m->npath,¶m->mpath,curpath); + MemFree(curpath); + } else { + Usage(1); + } + break; + case 'D': + if ((sep=strchr(argv[i],'='))!=NULL) { + if (sep!=argv[i]+2) { + FieldArrayAddDynamicValueConcat(¶m->symboldef,¶m->nsymb,¶m->msymb,argv[i]+2); + } else { + Usage(1); + } + } else { + Usage(1); + } + break; + case 'm': + switch (argv[i][2]) { + case 0: + param->rough=0.0; + return i; + case 'e': + if (argv[i][3]) Usage(1); + if (i+1maxerr=atoi(argv[++i]); + return i; + } + Usage(1); + break; + default:Usage(1);break; + } + Usage(1); + break; + case 's': + if (argv[i][2] && argv[i][3]) Usage(1); + + switch (argv[i][2]) { + case 0:param->export_sym=1;return 0; + case 'z': + param->export_sym=5;return 0; + case 'm': + param->export_multisym=1;return 0; + case 'b': + param->export_snabrk=1;return 0; + case 'p': + param->export_sym=2;return 0; + case 'w': + param->export_sym=3;return 0; + case 'c': + if (i+1export_sym=4; + param->flexible_export=TxtStrDup(argv[++i]); + param->flexible_export=MemRealloc(param->flexible_export,strlen(param->flexible_export)+3); + strcat(param->flexible_export,"\n"); + /* check export string */ + if (_internal_check_flexible(param->flexible_export)) return i; else Usage(1); + } + Usage(1); + break; + case 'l': + param->export_local=1;return 0; + case 'v': + param->export_var=1;return 0; + case 'q': + param->export_equ=1;return 0; + case 'a': + param->export_local=1; + param->export_var=1; + param->export_equ=1; + return 0; + case 's': + param->export_local=1; + param->export_sym=1; + param->export_sna=1;return 0; + default: + Usage(1); + break; + } + Usage(1); + break; + case 'l': + if (argv[i][2]) Usage(1); + if (i+1labelfilename,argv[++i]); + break; + } + Usage(1); + break; + case 'o': + if (argv[i][2] && argv[i][3]) Usage(1); + switch (argv[i][2]) { + case 0: + if (i+1outputfilename==NULL) { + param->outputfilename=argv[++i]; + break; + } + Usage(1); + break; + case 'a': + param->automatic_radix=1; + break; + case 't': + if (i+1tape_name==NULL) { + param->tape_name=argv[++i]; + break; + } + Usage(1); + break; + case 'r': + if (i+1rom_name==NULL) { + param->rom_name=argv[++i]; + break; + } + Usage(1); + break; + case 'i': + if (i+1snapshot_name==NULL) { + param->snapshot_name=argv[++i]; + break; + } + Usage(1); + break; + case 'l': + if (i+1cprinfo_name==NULL) { + param->cprinfo_name=argv[++i]; + break; + } + Usage(1); + break; + case 'b': + if (i+1binary_name==NULL) { + param->binary_name=argv[++i]; + break; + } + Usage(1); + break; + case 'c': + if (i+1cartridge_name==NULL) { + param->cartridge_name=argv[++i]; + break; + } + Usage(1); + break; + case 'k': + if (i+1breakpoint_name==NULL) { + param->breakpoint_name=argv[++i]; + break; + } + Usage(1); + break; + case 's': + if (i+1symbol_name==NULL) { + param->symbol_name=argv[++i]; + break; + } + Usage(1); + break; + default: + Usage(1); + break; + } + break; + case 'd':if (!argv[i][2]) printf("deprecated option -d\n"); else Usage(1); + break; + case 'a':if (!argv[i][2]) printf("deprecated option -a\n"); else Usage(1); + break; + case 'c':if (!argv[i][2]) printf("deprecated option -c\n"); else Usage(1); + break; + case 'v': + if (!argv[i][2]) { + param->display_stats=1; + } else if (argv[i][2]=='2') { + param->v2=1; + } + break; + case 'n':if (!argv[i][2]) Licenses(); else Usage(1); + case 'h':Usage(1);break; + default: + Usage(1);break; + } + } else { + if (param->filename==NULL) { + param->filename=TxtStrDup(argv[i]); + } else if (param->outputfilename==NULL) { + param->outputfilename=argv[i]; + } else Usage(1); + } + return i; +} + +/* + GetParametersFromCommandLine + retrieve parameters from command line and fill pointers to file names +*/ +void GetParametersFromCommandLine(int argc, char **argv, struct s_parameter *param) +{ + #undef FUNC + #define FUNC "GetParametersFromCommandLine" + int i; + + for (i=1;ifilename) Usage(0); + if (param->export_local && !param->export_sym) Usage(1); // à revoir? +} + +/* + main + + check parameters + execute the main processing +*/ + + +int main(int argc, char **argv) +{ + #undef FUNC + #define FUNC "main" + + struct s_parameter param={0}; + int ret; + + param.cprinfo=1; + param.maxerr=20; + param.rough=0.5; + param.module_separator='_'; + + GetParametersFromCommandLine(argc,argv,¶m); + ret=Rasm(¶m); + #ifdef RDD + /* private dev lib tools */ +printf("checking memory\n"); + CloseLibrary(); + #endif + exit(ret); + return 0; // Open WATCOM Warns without this... +} + +#endif diff --git a/tools/rasm/rasm.h b/tools/rasm/rasm.h index 211cf9e..4899446 100644 --- a/tools/rasm/rasm.h +++ b/tools/rasm/rasm.h @@ -14,13 +14,20 @@ struct s_rasm_info { int nberror,maxerror; struct s_debug_symbol *symbol; int nbsymbol,maxsymbol; + int run,start; + unsigned char *emuram; + int lenram; }; +#ifndef INSIDE_RASM //extern "C" { int RasmAssemble(const char *datain, int lenin, unsigned char **dataout, int *lenout); int RasmAssembleInfo(const char *datain, int lenin, unsigned char **dataout, int *lenout, struct s_rasm_info **debug); +int RasmAssembleInfoIntoRAM(const char *datain, int lenin, struct s_rasm_info **debug, unsigned char *emuram, int ramsize); void RasmFreeInfoStruct(struct s_rasm_info *debug); //}; +#endif + diff --git a/tools/rasm/rasm_v0120.c b/tools/rasm/rasm_v0120.c deleted file mode 100644 index 2c0a96a..0000000 --- a/tools/rasm/rasm_v0120.c +++ /dev/null @@ -1,17472 +0,0 @@ -#define PROGRAM_NAME "RASM" -#define PROGRAM_VERSION "0.120" -#define PROGRAM_DATE "xx/12/2019" -#define PROGRAM_COPYRIGHT "© 2017 BERGE Edouard / roudoudou from Resistance" - -#define RASM_VERSION PROGRAM_NAME" v"PROGRAM_VERSION" (build "PROGRAM_DATE")" -#define RASM_SNAP_VERSION PROGRAM_NAME" v"PROGRAM_VERSION - -#define TRACE_GENERALE 0 -#define TRACE_PREPRO 0 -#define TRACE_ASSEMBLE 0 -#define TRACE_COMPUTE_EXPRESSION 0 -#define TRACE_HEXBIN 0 -#define TRACE_MAKEAMSDOSREAL 0 -#define TRACE_STRUCT 0 -#define TRACE_EDSK 0 - - - -/*** -Rasm (roudoudou assembler) Z80 assembler - -doc & latest official release at: http://www.cpcwiki.eu/forum/programming/rasm-z80-assembler-in-beta/ - -You may send requests/bugs in the same topic - ------------------------------------------------------------------------------------------------------ -This software is using MIT "expat" license - -« Copyright © BERGE Edouard (roudoudou) - -Permission is hereby granted, free of charge,to any person obtaining a copy of this software -and associated documentation/source files of RASM, 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. » ------------------------------------------------------------------------------------------------------ -Linux compilation with GCC or Clang: -cc rasm_v0116.c -O2 -lm -lrt -march=native -o rasm -strip rasm - -Windows compilation with Visual studio: -cl.exe rasm_v0116.c -O2 -Ob3 - -pure MS-DOS 32 bits compilation with Watcom: -wcl386 rasm_v0116.c -6r -6s -fp6 -d0 -k4000000 -ox /bt=DOS /l=dos4g - -MorphOS compilation (ixemul): -ppc-morphos-gcc-5 -O2 -c -o rasm rasm_v0116.c -strip rasm - -MacOS compilation: -cc rasm_v0116.c -O2 -lm -march=native -o rasm - -*/ - -#ifdef __WATCOMC__ -#define OS_WIN 1 -#endif - -#ifdef _WIN32 -#define OS_WIN 1 -#endif - -#ifdef _WIN64 -#define OS_WIN 1 -#endif - -#ifndef RDD - /* public lib */ - #include"minilib.h" -#else - /* private dev lib wont be published */ - #include"../tools/library.h" - #define TxtSplitWithChar _internal_TxtSplitWithChar -#endif - -#ifndef NO_3RD_PARTIES -#define __FILENAME__ "3rd parties" -/* 3rd parties compression */ -#include"zx7.h" -#include"lz4.h" -#include"exomizer.h" -#endif - -#ifdef __MORPHOS__ -/* Add standard version string to executable */ -const char __attribute__((section(".text"))) ver_version[]={ "\0$VER: "PROGRAM_NAME" "PROGRAM_VERSION" ("PROGRAM_DATE") "PROGRAM_COPYRIGHT"" }; -#endif - -#undef __FILENAME__ -#define __FILENAME__ "rasm.c" - -#ifndef OS_WIN -#define KNORMAL "\x1B[0m" -#define KERROR "\x1B[31m" -#define KAYGREEN "\x1B[32m" -#define KWARNING "\x1B[33m" -#define KBLUE "\x1B[34m" -#define KVERBOSE "\x1B[36m" -#define KIO "\x1B[97m" -#else -#define KNORMAL "" -#define KERROR "Error: " -#define KAYGREEN "" -#define KWARNING "Warning: " -#define KBLUE "" -#define KVERBOSE "" -#define KIO "" -#endif - -/******************************************************************* - c o m m a n d l i n e p a r a m e t e r s -*******************************************************************/ -enum e_dependencies_type { -E_DEPENDENCIES_NO=0, -E_DEPENDENCIES_LIST, -E_DEPENDENCIES_MAKE -}; - -struct s_parameter { - char **labelfilename; - char *filename; - char *outputfilename; - int automatic_radix; - int export_local; - int export_var; - int export_equ; - int export_sym; - int export_multisym; - int export_tape; - char *flexible_export; - int export_sna; - int export_snabrk; - int export_brk; - int nowarning; - int checkmode; - int dependencies; - int maxerr; - int macrovoid; - int extended_error; - int edskoverwrite; - float rough; - int as80,dams; - int v2; - int warn_unused; - char *symbol_name; - char *binary_name; - char *cartridge_name; - char *snapshot_name; - char *tape_name; - char *breakpoint_name; - char **symboldef; - int nsymb,msymb; - char **pathdef; - int npath,mpath; -}; - - - -/******************************************************************* - c o m p u t e o p e r a t i o n s f o r c a l c u l a t o r -*******************************************************************/ - -enum e_compute_operation_type { -E_COMPUTE_OPERATION_PUSH_DATASTC=0, -E_COMPUTE_OPERATION_OPEN=1, -E_COMPUTE_OPERATION_CLOSE=2, -E_COMPUTE_OPERATION_ADD=3, -E_COMPUTE_OPERATION_SUB=4, -E_COMPUTE_OPERATION_DIV=5, -E_COMPUTE_OPERATION_MUL=6, -E_COMPUTE_OPERATION_AND=7, -E_COMPUTE_OPERATION_OR=8, -E_COMPUTE_OPERATION_MOD=9, -E_COMPUTE_OPERATION_XOR=10, -E_COMPUTE_OPERATION_NOT=11, -E_COMPUTE_OPERATION_SHL=12, -E_COMPUTE_OPERATION_SHR=13, -E_COMPUTE_OPERATION_BAND=14, -E_COMPUTE_OPERATION_BOR=15, -E_COMPUTE_OPERATION_LOWER=16, -E_COMPUTE_OPERATION_GREATER=17, -E_COMPUTE_OPERATION_EQUAL=18, -E_COMPUTE_OPERATION_NOTEQUAL=19, -E_COMPUTE_OPERATION_LOWEREQ=20, -E_COMPUTE_OPERATION_GREATEREQ=21, -/* math functions */ -E_COMPUTE_OPERATION_SIN=22, -E_COMPUTE_OPERATION_COS=23, -E_COMPUTE_OPERATION_INT=24, -E_COMPUTE_OPERATION_FLOOR=25, -E_COMPUTE_OPERATION_ABS=26, -E_COMPUTE_OPERATION_LN=27, -E_COMPUTE_OPERATION_LOG10=28, -E_COMPUTE_OPERATION_SQRT=29, -E_COMPUTE_OPERATION_ASIN=30, -E_COMPUTE_OPERATION_ACOS=31, -E_COMPUTE_OPERATION_ATAN=32, -E_COMPUTE_OPERATION_EXP=33, -E_COMPUTE_OPERATION_LOW=34, -E_COMPUTE_OPERATION_HIGH=35, -E_COMPUTE_OPERATION_PSG=36, -E_COMPUTE_OPERATION_RND=37, -E_COMPUTE_OPERATION_FRAC=38, -E_COMPUTE_OPERATION_CEIL=39, -E_COMPUTE_OPERATION_GET_R=40, -E_COMPUTE_OPERATION_GET_V=41, -E_COMPUTE_OPERATION_GET_B=42, -E_COMPUTE_OPERATION_SET_R=43, -E_COMPUTE_OPERATION_SET_V=44, -E_COMPUTE_OPERATION_SET_B=45, -E_COMPUTE_OPERATION_END=46 -}; - -struct s_compute_element { -enum e_compute_operation_type operator; -double value; -int priority; -}; - -struct s_compute_core_data { - /* evaluator v3 may be recursive */ - char *varbuffer; - int maxivar; - struct s_compute_element *tokenstack; - int maxtokenstack; - struct s_compute_element *operatorstack; - int maxoperatorstack; -}; - -/*********************************************************** - w a v h e a d e r f o r a u d i o i m p o r t -***********************************************************/ -struct s_wav_header { -unsigned char ChunkID[4]; -unsigned char ChunkSize[4]; -unsigned char Format[4]; -unsigned char SubChunk1ID[4]; -unsigned char SubChunk1Size[4]; -unsigned char AudioFormat[2]; -unsigned char NumChannels[2]; -unsigned char SampleRate[4]; -unsigned char ByteRate[4]; -unsigned char BlockAlign[2]; -unsigned char BitsPerSample[2]; -unsigned char SubChunk2ID[4]; -unsigned char SubChunk2Size[4]; -}; - -enum e_audio_sample_type { -AUDIOSAMPLE_SMP, -AUDIOSAMPLE_SM2, -AUDIOSAMPLE_SM4, -AUDIOSAMPLE_DMA, -AUDIOSAMPLE_END -}; - -/*********************************************************************** - e x p r e s s i o n t y p e s f o r d e l a y e d w r i t e -***********************************************************************/ -enum e_expression { - E_EXPRESSION_J8, /* relative 8bits jump */ - E_EXPRESSION_0V8, /* 8 bits value to current adress */ - E_EXPRESSION_V8, /* 8 bits value to current adress+1 */ - E_EXPRESSION_V16, /* 16 bits value to current adress+1 */ - E_EXPRESSION_V16C, /* 16 bits value to current adress+1 */ - E_EXPRESSION_0V16, /* 16 bits value to current adress */ - E_EXPRESSION_0V32, /* 32 bits value to current adress */ - E_EXPRESSION_0VR, /* AMSDOS real value (5 bytes) to current adress */ - E_EXPRESSION_IV8, /* 8 bits value to current adress+2 */ - E_EXPRESSION_IV81, /* 8 bits value+1 to current adress+2 */ - E_EXPRESSION_3V8, /* 8 bits value to current adress+3 used with LD (IX+n),n */ - E_EXPRESSION_IV16, /* 16 bits value to current adress+2 */ - E_EXPRESSION_RST, /* the offset of RST is translated to the opcode */ - E_EXPRESSION_IM, /* the interrupt mode is translated to the opcode */ - E_EXPRESSION_RUN, /* delayed RUN value */ - E_EXPRESSION_ZXRUN, /* delayed RUN value for ZX snapshot */ - E_EXPRESSION_ZXSTACK,/* delayed STACK value for ZX snapshot */ - E_EXPRESSION_BRS /* delayed shifting for BIT, RES, SET */ -}; - -struct s_expression { - char *reference; /* backup when used inside loop (or macro?) */ - int iw; /* word index in the main wordlist */ - int o; /* offset de depart 0, 1 ou 3 selon l'opcode */ - int ptr; /* offset courant pour calculs relatifs */ - int wptr; /* where to write the result */ - enum e_expression zetype; /* type of delayed write */ - int lz; /* lz zone */ - int ibank; /* ibank of expression */ - int iorgzone; /* org of expression */ -}; - -struct s_expr_dico { - char *name; - int crc; - int autorise_export; - double v; - int used; - int iw; -}; - -struct s_label { - char *name; /* is alloced for local repeat or struct OR generated global -> in this case iw=-1 */ - int iw; /* index of the word of label name */ - int crc; /* crc of the label name */ - int ptr; /* "physical" adress */ - int lz; /* is the label in a crunched section (or after)? */ - int iorgzone; /* org of label */ - int ibank; /* current CPR bank / always zero in classic mode */ - int local; - /* errmsg */ - int fileidx; - int fileline; - int autorise_export,backidx; - int used; -}; - -struct s_alias { - char *alias; - char *translation; - int crc,len,autorise_export; - int iw; - int used; -}; - -struct s_ticker { - char *varname; - int crc; - long nopstart; - long tickerstart; -}; - -/*********************************************************************** - m e r k e l t r e e s f o r l a b e l, v a r, a l i a s -***********************************************************************/ -struct s_crclabel_tree { - struct s_crclabel_tree *radix[256]; - struct s_label *label; - int nlabel,mlabel; -}; -struct s_crcdico_tree { - struct s_crcdico_tree *radix[256]; - struct s_expr_dico *dico; - int ndico,mdico; -}; -struct s_crcused_tree { - struct s_crcused_tree *radix[256]; - char **used; - int nused,mused; -}; -struct s_crcstring_tree { - struct s_crcstring_tree *radix[256]; - char **text; - int ntext,mtext; - char **replace; - int nreplace,mreplace; -}; -/************************************************* - m e m o r y s e c t i o n -*************************************************/ -struct s_lz_section { - int iw; - int memstart,memend; - int lzversion; /* 4 -> LZ4 / 7 -> ZX7 / 48 -> LZ48 / 49 -> LZ49 / 8 -> Exomizer */ - int iorgzone; - int ibank; - /* idx backup */ - int iexpr; - int ilabel; -}; - -struct s_orgzone { - int ibank,protect; - int memstart,memend; - int ifile,iline; - int nocode; -}; - -/************************************************** - i n c b i n s t o r a g e -**************************************************/ -struct s_hexbin { - unsigned char *data; - int datalen,rawlen; - char *filename; - int crunch; -}; - -/************************************************** - e d s k m a n a g e m e n t -**************************************************/ -struct s_edsk_sector_global_struct { -unsigned char track; -unsigned char side; -unsigned char id; -unsigned char size; -unsigned char st1; -unsigned char st2; -unsigned short int length; -unsigned char *data; -}; - -struct s_edsk_track_global_struct { -int sectornumber; -/* information purpose */ -int sectorsize; -int gap3length; -int fillerbyte; -int datarate; -int recordingmode; -struct s_edsk_sector_global_struct *sector; -}; - -struct s_edsk_global_struct { -int tracknumber; -int sidenumber; -int tracksize; /* DSK legacy */ -struct s_edsk_track_global_struct *track; -}; - -struct s_edsk_wrapper_entry { -unsigned char user; -unsigned char filename[11]; -unsigned char subcpt; -unsigned char extendcounter; -unsigned char reserved; -unsigned char rc; -unsigned char blocks[16]; -}; - -struct s_edsk_wrapper { -char *edsk_filename; -struct s_edsk_wrapper_entry entry[64]; -int nbentry; -unsigned char blocks[178][1024]; /* DATA format */ -int face; -}; - -struct s_save { - int ibank; - int ioffset; - int isize; - int iw,irun; - int amsdos,hobeta; - int tape,dsk,face,iwdskname; -}; - - -/******************** - L O O P S -********************/ - -enum e_loop_style { -E_LOOPSTYLE_REPEATN, -E_LOOPSTYLE_REPEATUNTIL, -E_LOOPSTYLE_WHILE -}; - -struct s_repeat { - int start; - int cpt; - int value; - int maxim; - int repeat_counter; - char *repeatvar; - int repeatcrc; -}; - -struct s_whilewend { - int start; - int cpt; - int value; - int maxim; - int while_counter; -}; - -struct s_switchcase { - int refval; - int execute; - int casematch; -}; - -struct s_repeat_index { - int ifile; - int ol,oidx; - int cl,cidx; -}; - - -enum e_ifthen_type { -E_IFTHEN_TYPE_IF=0, -E_IFTHEN_TYPE_IFNOT=1, -E_IFTHEN_TYPE_IFDEF=2, -E_IFTHEN_TYPE_IFNDEF=3, -E_IFTHEN_TYPE_ELSE=4, -E_IFTHEN_TYPE_ELSEIF=5, -E_IFTHEN_TYPE_IFUSED=6, -E_IFTHEN_TYPE_IFNUSED=7, -E_IFTHEN_TYPE_END -}; - -struct s_ifthen { - char *filename; - int line,v; - enum e_ifthen_type type; -}; - -/************************************************** - w o r d p r o c e s s i n g -**************************************************/ -struct s_wordlist { - char *w; - int l,t,e; /* e=1 si egalite dans le mot */ - int ifile; -}; - -struct s_macro { - char *mnemo; - int crc; - /* une macro concatene des chaines et des parametres */ - struct s_wordlist *wc; - int nbword,maxword; - /**/ - char **param; - int nbparam; -}; - -struct s_macro_position { - int start,end,value; -}; - -/* preprocessing only */ -struct s_macro_fast { - char *mnemo; - int crc; -}; - -struct s_math_keyword { - char *mnemo; - int crc; - enum e_compute_operation_type operation; -}; - -struct s_expr_word { - char *w; - int aw; - int op; - int comma; - int fct; - double v; -}; - -struct s_listing { - char *listing; - int ifile; - int iline; -}; - -enum e_tagtranslateoption { -E_TAGOPTION_NONE=0, -E_TAGOPTION_REMOVESPACE=1, -E_TAGOPTION_PRESERVE=2 -}; - -#ifdef RASM_THREAD -struct s_rasm_thread { - pthread_t thread; - int lz; - unsigned char *datain; - int datalen; - unsigned char *dataout; - int lenout; - int status; -}; -#endif - - -/********************************************************* - S N A P S H O T E X P O R T -*********************************************************/ -/* extension 4Mo = 256 slots + 4 slots 64K de RAM par défaut => 260 */ - -#define BANK_MAX_NUMBER 260 - -struct s_snapshot_symbol { - unsigned char size; - unsigned char name[256]; - unsigned char reserved[6]; - unsigned char bigendian_adress[2]; -}; - - -struct s_zxsnapshot { - - unsigned int run; - unsigned int stack; -}; - -struct s_snapshot { - char idmark[8]; - char unused1[8]; - unsigned char version; /* 3 */ - struct { - struct { - unsigned char F; - unsigned char A; - unsigned char C; - unsigned char B; - unsigned char E; - unsigned char D; - unsigned char L; - unsigned char H; - }general; - unsigned char R; - unsigned char regI; /* I incompatible with tgmath.h */ - unsigned char IFF0; - unsigned char IFF1; - unsigned char LX; - unsigned char HX; - unsigned char LY; - unsigned char HY; - unsigned char LSP; - unsigned char HSP; - unsigned char LPC; - unsigned char HPC; - unsigned char IM; /* 0,1,2 */ - struct { - unsigned char F; - unsigned char A; - unsigned char C; - unsigned char B; - unsigned char E; - unsigned char D; - unsigned char L; - unsigned char H; - }alternate; - }registers; - - struct { - unsigned char selectedpen; - unsigned char palette[17]; - unsigned char multiconfiguration; - }gatearray; - unsigned char ramconfiguration; - struct { - unsigned char selectedregister; - unsigned char registervalue[18]; - }crtc; - unsigned char romselect; - struct { - unsigned char portA; - unsigned char portB; - unsigned char portC; - unsigned char control; - }ppi; - struct { - unsigned char selectedregister; - unsigned char registervalue[16]; - }psg; - unsigned char dumpsize[2]; /* 64 then use extended memory chunks */ - - unsigned char CPCType; /* 0=464 / 1=664 / 2=6128 / 4=6128+ / 5=464+ / 6=GX4000 */ - unsigned char interruptnumber; - unsigned char multimodebytes[6]; - unsigned char unused2[0x9C-0x75]; - - /* offset #9C */ - struct { - unsigned char motorstate; - unsigned char physicaltrack; - }fdd; - unsigned char unused3[3]; - unsigned char printerstrobe; - unsigned char unused4[2]; - struct { - unsigned char model; /* 0->4 */ - unsigned char unused5[4]; - unsigned char HCC; - unsigned char unused; - unsigned char CLC; - unsigned char RLC; - unsigned char VTC; - unsigned char HSC; - unsigned char VSC; - unsigned short int flags; - }crtcstate; - unsigned char vsyncdelay; - unsigned char interruptscanlinecounter; - unsigned char interruptrequestflag; - unsigned char unused6[0xFF-0xB5+1]; -}; - -struct s_snapshot_chunks { - unsigned char chunkname[4]; /* MEM1 -> MEM8 */ - unsigned int chunksize; -}; - -struct s_breakpoint { - int address; - int bank; -}; - - -/********************************* - S T R U C T U R E S -*********************************/ -enum e_rasmstructfieldtype { -E_RASMSTRUCTFIELD_BYTE, -E_RASMSTRUCTFIELD_WORD, -E_RASMSTRUCTFIELD_LONG, -E_RASMSTRUCTFIELD_REAL, -E_RASMSTRUCTFIELD_END -}; -struct s_rasmstructfield { - char *fullname; - char *name; - int offset; - int size; - int crc; - /* filler */ - unsigned char *data; - int idata,mdata; - enum e_rasmstructfieldtype zetype; -}; - -struct s_rasmstruct { - char *name; - int crc; - int size; - int ptr; - int nbelem; - /* fields */ - struct s_rasmstructfield *rasmstructfield; - int irasmstructfield,mrasmstructfield; -}; - -/********************************* - D E B U G -*********************************/ -struct s_debug_error { - char *filename; - int line; - char *msg; - int lenmsg,lenfilename; -}; -struct s_debug_symbol { - char *name; - int v; -}; -struct s_rasm_info { - struct s_debug_error *error; - int nberror,maxerror; - struct s_debug_symbol *symbol; - int nbsymbol,maxsymbol; -}; - -/******************************************* - G L O B A L S T R U C T -*******************************************/ -struct s_assenv { - /* current memory */ - int maxptr; - /* CPR memory */ - unsigned char **mem; - int iwnamebank[BANK_MAX_NUMBER]; - int nbbank,maxbank; - int forcetape,forcezx,forcecpr,forceROM,bankmode,activebank,amsdos,forcesnapshot,packedbank; - struct s_snapshot snapshot; - struct s_zxsnapshot zxsnapshot; - int bankset[BANK_MAX_NUMBER>>2]; /* 64K selected flag */ - int bankused[BANK_MAX_NUMBER]; /* 16K selected flag */ - int bankgate[BANK_MAX_NUMBER+1]; - int setgate[BANK_MAX_NUMBER+1]; - int rundefined; - /* parsing */ - struct s_wordlist *wl; - int nbword; - int idx,stage; - char *label_filename; - int label_line; - char **filename; - int ifile,maxfile; - int nberr,flux; - int fastmatch[256]; - unsigned char charset[256]; - int maxerr,extended_error,nowarning; - /* ORG tracking */ - int codeadr,outputadr,nocode; - int codeadrbackup,outputadrbackup; - int minadr,maxadr; - struct s_orgzone *orgzone; - int io,mo; - /* Struct */ - struct s_rasmstruct *rasmstruct; - int irasmstruct,mrasmstruct; - int getstruct; - int backup_outputadr,backup_codeadr; - char *backup_filename; - int backup_line; - struct s_rasmstruct *rasmstructalias; - int irasmstructalias,mrasmstructalias; - /* expressions */ - struct s_expression *expression; - int ie,me; - int maxam,as80,dams; - float rough; - struct s_compute_core_data *computectx,ctx1,ctx2; - struct s_crcstring_tree stringtree; - /* label */ - struct s_label *label; - int il,ml; - struct s_crclabel_tree labeltree; /* fast label access */ - char *module; - int modulen; - struct s_breakpoint *breakpoint; - int ibreakpoint,maxbreakpoint; - char *lastgloballabel; - char *lastsuperglobal; - int lastgloballabellen, lastglobalalloc; - /* repeat */ - struct s_repeat *repeat; - int ir,mr; - /* while/wend */ - struct s_whilewend *whilewend; - int iw,mw; - /* if/then/else */ - //int *ifthen; - struct s_ifthen *ifthen; - int ii,mi; - /* switch/case */ - struct s_switchcase *switchcase; - int isw,msw; - /* expression dictionnary */ - struct s_expr_dico *dico; - int idic,mdic; - struct s_crcdico_tree dicotree; /* fast dico access */ - struct s_crcused_tree usedtree; /* fast used access */ - /* ticker */ - struct s_ticker *ticker; - int iticker,mticker; - long tick,nop; - /* crunch section flag */ - struct s_lz_section *lzsection; - int ilz,mlz; - int lz,curlz; - /* macro */ - struct s_macro *macro; - int imacro,mmacro; - int macrovoid; - /* labels locaux */ - int repeatcounter,whilecounter,macrocounter; - struct s_macro_position *macropos; - int imacropos,mmacropos; - /* alias */ - struct s_alias *alias; - int ialias,malias; - /* hexbin */ - struct s_rasm_thread **rasm_thread; - int irt,mrt; - struct s_hexbin *hexbin; - int ih,mh; - char **includepath; - int ipath,mpath; - /* automates */ - char AutomateExpressionValidCharExtended[256]; - char AutomateExpressionValidCharFirst[256]; - char AutomateExpressionValidChar[256]; - char AutomateExpressionDecision[256]; - char AutomateValidLabelFirst[256]; - char AutomateValidLabel[256]; - char AutomateDigit[256]; - char AutomateHexa[256]; - struct s_compute_element AutomateElement[256]; - unsigned char psgtab[256]; - unsigned char psgfine[256]; - /* output */ - char *outputfilename; - int export_sym,export_local,export_multisym; - int export_var,export_equ; - int export_sna,export_snabrk; - int export_brk,export_tape; - int autorise_export; - char *flexible_export; - char *breakpoint_name; - char *symbol_name; - char *binary_name; - char *cartridge_name; - char *snapshot_name; - struct s_save *save; - int nbsave,maxsave; - int current_run_idx; - struct s_edsk_wrapper *edsk_wrapper; - int nbedskwrapper,maxedskwrapper; - int edskoverwrite; - int checkmode,dependencies; - int stop; - int warn_unused; - /* debug */ - struct s_rasm_info debug; - struct s_rasm_info **retdebug; - int debug_total_len; -}; - -/************************************* - D I R E C T I V E S -*************************************/ -struct s_asm_keyword { - char *mnemo; - int crc; - void (*makemnemo)(struct s_assenv *ae); -}; - -struct s_math_keyword math_keyword[]={ -{"SIN",0,E_COMPUTE_OPERATION_SIN}, -{"COS",0,E_COMPUTE_OPERATION_COS}, -{"INT",0,E_COMPUTE_OPERATION_INT}, -{"ABS",0,E_COMPUTE_OPERATION_ABS}, -{"LN",0,E_COMPUTE_OPERATION_LN}, -{"LOG10",0,E_COMPUTE_OPERATION_LOG10}, -{"SQRT",0,E_COMPUTE_OPERATION_SQRT}, -{"FLOOR",0,E_COMPUTE_OPERATION_FLOOR}, -{"ASIN",0,E_COMPUTE_OPERATION_ASIN}, -{"ACOS",0,E_COMPUTE_OPERATION_ACOS}, -{"ATAN",0,E_COMPUTE_OPERATION_ATAN}, -{"EXP",0,E_COMPUTE_OPERATION_EXP}, -{"LO",0,E_COMPUTE_OPERATION_LOW}, -{"HI",0,E_COMPUTE_OPERATION_HIGH}, -{"PSGVALUE",0,E_COMPUTE_OPERATION_PSG}, -{"RND",0,E_COMPUTE_OPERATION_RND}, -{"FRAC",0,E_COMPUTE_OPERATION_FRAC}, -{"CEIL",0,E_COMPUTE_OPERATION_CEIL}, -{"GETR",0,E_COMPUTE_OPERATION_GET_R}, -{"GETV",0,E_COMPUTE_OPERATION_GET_V}, -{"GETG",0,E_COMPUTE_OPERATION_GET_V}, -{"GETB",0,E_COMPUTE_OPERATION_GET_B}, -{"SETR",0,E_COMPUTE_OPERATION_SET_R}, -{"SETV",0,E_COMPUTE_OPERATION_SET_V}, -{"SETG",0,E_COMPUTE_OPERATION_SET_V}, -{"SETB",0,E_COMPUTE_OPERATION_SET_B}, -{"",0,-1} -}; - -#define CRC_SWITCH 0x01AEDE4A -#define CRC_CASE 0x0826B794 -#define CRC_DEFAULT 0x9A0DAC7D -#define CRC_BREAK 0xCD364DDD -#define CRC_ENDSWITCH 0x18E9FB21 - -#define CRC_ELSEIF 0xE175E230 -#define CRC_ELSE 0x3FF177A1 -#define CRC_ENDIF 0xCD5265DE -#define CRC_IF 0x4BD52507 -#define CRC_IFDEF 0x4CB29DD6 -#define CRC_UNDEF 0xCCD2FDEA -#define CRC_IFNDEF 0xD9AD0824 -#define CRC_IFNOT 0x4CCAC9F8 -#define CRC_WHILE 0xBC268FF1 -#define CRC_UNTIL 0xCC12A604 -#define CRC_MEND 0xFFFD899C -#define CRC_ENDM 0x3FF9559C -#define CRC_MACRO 0x64AA85EA -#define CRC_IFUSED 0x91752638 -#define CRC_IFNUSED 0x1B39A886 - -#define CRC_SIN 0xE1B71962 -#define CRC_COS 0xE077C55D - -#define CRC_0 0x7A98A6A8 -#define CRC_1 0x7A98A6A9 -#define CRC_2 0x7A98A6AA - - -#define CRC_NC 0x4BD52B09 -#define CRC_Z 0x7A98A6D2 -#define CRC_NZ 0x4BD52B20 -#define CRC_P 0x7A98A6C8 -#define CRC_PO 0x4BD53717 -#define CRC_PE 0x4BD5370D -#define CRC_M 0x7A98A6C5 - -/* 8 bits registers */ -#define CRC_F 0x7A98A6BE -#define CRC_I 0x7A98A6C1 -#define CRC_R 0x7A98A6CA -#define CRC_A 0x7A98A6B9 -#define CRC_B 0x7A98A6BA -#define CRC_C 0x7A98A6BB -#define CRC_D 0x7A98A6BC -#define CRC_E 0x7A98A6BD -#define CRC_H 0x7A98A6C0 -#define CRC_L 0x7A98A6C4 -/* dual naming */ -#define CRC_XH 0x4BD50718 -#define CRC_XL 0x4BD5071C -#define CRC_YH 0x4BD50519 -#define CRC_YL 0x4BD5051D -#define CRC_HX 0x4BD52718 -#define CRC_LX 0x4BD52F1C -#define CRC_HY 0x4BD52719 -#define CRC_LY 0x4BD52F1D -#define CRC_IXL 0xE19F1765 -#define CRC_IXH 0xE19F1761 -#define CRC_IYL 0xE19F1166 -#define CRC_IYH 0xE19F1162 - -/* 16 bits registers */ -#define CRC_BC 0x4BD5D2FD -#define CRC_DE 0x4BD5DF01 -#define CRC_HL 0x4BD5270C -#define CRC_IX 0x4BD52519 -#define CRC_IY 0x4BD5251A -#define CRC_SP 0x4BD5311B -#define CRC_AF 0x4BD5D4FF -/* memory convention */ -#define CRC_MHL 0xD0765F5D -#define CRC_MDE 0xD0467D52 -#define CRC_MBC 0xD05E694E -#define CRC_MIX 0xD072B76A -#define CRC_MIY 0xD072B16B -#define CRC_MSP 0xD01A876C -#define CRC_MC 0xE018210C -/* struct parsing */ -#define CRC_DEFB 0x37D15389 -#define CRC_DB 0x4BD5DEFE -#define CRC_DEFW 0x37D1539E -#define CRC_DW 0x4BD5DF13 -#define CRC_DEFI 0x37D15390 -#define CRC_DEFS 0x37D1539A -#define CRC_DS 0x4BD5DF0F -#define CRC_DEFR 0x37D15399 -#define CRC_DR 0x4BD5DF0E - -/* struct declaration use special instructions for defines */ -int ICRC_DEFB,ICRC_DEFW,ICRC_DEFI,ICRC_DEFR,ICRC_DEFS,ICRC_DB,ICRC_DW,ICRC_DR,ICRC_DS; -/* need to pre-declare var */ -extern struct s_asm_keyword instruction[]; - -/* -# base=16 -% base=2 -0-9 base=10 -A-Z variable ou fonction (cos, sin, tan, sqr, pow, mod, and, xor, mod, ...) -+*-/&^m| operateur -*/ - -#define AutomateExpressionValidCharExtendedDefinition "0123456789.ABCDEFGHIJKLMNOPQRSTUVWXYZ_{}@+-*/~^$#%§<=>|&" -#define AutomateExpressionValidCharFirstDefinition "#%0123456789.ABCDEFGHIJKLMNOPQRSTUVWXYZ_@${" -#define AutomateExpressionValidCharDefinition "0123456789.ABCDEFGHIJKLMNOPQRSTUVWXYZ_{}@$" -#define AutomateValidLabelFirstDefinition ".ABCDEFGHIJKLMNOPQRSTUVWXYZ_@" -#define AutomateValidLabelDefinition "0123456789.ABCDEFGHIJKLMNOPQRSTUVWXYZ_@{}" -#define AutomateDigitDefinition ".0123456789" -#define AutomateHexaDefinition "0123456789ABCDEF" - -#ifndef NO_3RD_PARTIES -unsigned char *LZ4_crunch(unsigned char *data, int zelen, int *retlen){ - unsigned char *lzdest=NULL; - lzdest=MemMalloc(65536); - *retlen=LZ4_compress_HC((char*)data,(char*)lzdest,zelen,65536,9); - return lzdest; -} -#endif -unsigned char *LZ48_encode_legacy(unsigned char *data, int length, int *retlength); -#define LZ48_crunch LZ48_encode_legacy -unsigned char *LZ49_encode_legacy(unsigned char *data, int length, int *retlength); -#define LZ49_crunch LZ49_encode_legacy - - -/* - * optimised reading of text file in one shot - */ -unsigned char *_internal_readbinaryfile(char *filename, int *filelength) -{ - #undef FUNC - #define FUNC "_internal_readbinaryfile" - - unsigned char *binary_data=NULL; - - *filelength=FileGetSize(filename); - binary_data=MemMalloc((*filelength)+1); - /* we try to read one byte more to close the file just after the read func */ - if (FileReadBinary(filename,(char*)binary_data,(*filelength)+1)!=*filelength) { - logerr("Cannot fully read %s",filename); - exit(INTERNAL_ERROR); - } - return binary_data; -} -char **_internal_readtextfile(char *filename, char replacechar) -{ - #undef FUNC - #define FUNC "_internal_readtextfile" - - char **lines_buffer=NULL; - unsigned char *bigbuffer; - int nb_lines=0,max_lines=0,i=0,e=0; - int file_size; - - bigbuffer=_internal_readbinaryfile(filename,&file_size); - - while (i=max_lines) { - max_lines=max_lines*2+10; - lines_buffer=MemRealloc(lines_buffer,(max_lines+1)*sizeof(char **)); - } - lines_buffer[nb_lines]=MemMalloc(e-i+1); - memcpy(lines_buffer[nb_lines],bigbuffer+i,e-i); - lines_buffer[nb_lines][e-i]=0; - if (0) - { - int yy; - for (yy=0;lines_buffer[nb_lines][yy];yy++) { - if (lines_buffer[nb_lines][yy]>31) printf("%c",lines_buffer[nb_lines][yy]); else printf("(0x%X)",lines_buffer[nb_lines][yy]); - } - printf("\n"); - } - nb_lines++; - i=e; - } - if (!max_lines) { - lines_buffer=MemMalloc(sizeof(char**)); - lines_buffer[0]=NULL; - } else { - lines_buffer[nb_lines]=NULL; - } - MemFree(bigbuffer); - return lines_buffer; -} - -#define FileReadLines(filename) _internal_readtextfile(filename,':') -#define FileReadLinesRAW(filename) _internal_readtextfile(filename,0x0D) -#define FileReadContent(filename,filesize) _internal_readbinaryfile(filename,filesize) - - -/*** - TxtReplace - - input: - in_str: string where replace will occur - in_substr: substring to look for - out_substr: replace substring - recurse: loop until no in_substr is found - - note: in_str MUST BE previously mallocated if out_substr is bigger than in_substr -*/ -#ifndef RDD -char *TxtReplace(char *in_str, char *in_substr, char *out_substr, int recurse) -{ - #undef FUNC - #define FUNC "TxtReplace" - - char *str_look,*m1,*m2; - char *out_str; - int sl,l1,l2,dif,cpt; - - if (in_str==NULL) - return NULL; - - sl=strlen(in_str); - l1=strlen(in_substr); - /* empty string, nothing to do except return empty string */ - if (!sl || !l1) - return in_str; - - l2=strlen(out_substr); - dif=l2-l1; - - /* replace string is small or equal in size, we dont realloc */ - if (dif<=0) - { - /* we loop while there is a replace to do */ - str_look=strstr(in_str,in_substr); - while (str_look!=NULL) - { - /* we copy the new string if his len is not null */ - if (l2) - memcpy(str_look,out_substr,l2); - /* only if len are different */ - if (l1!=l2) - { - /* we move the end of the string byte per byte - because memory locations overlap. This is - faster than memmove */ - m1=str_look+l1; - m2=str_look+l2; - while (*m1!=0) - { - *m2=*m1; - m1++;m2++; - } - /* we must copy the EOL */ - *m2=*m1; - } - /* look for next replace */ - if (!recurse) - str_look=strstr(str_look+l2,in_substr); - else - str_look=strstr(in_str,in_substr); - } - out_str=in_str; - } - else - { - /* we need to count each replace */ - cpt=0; - str_look=strstr(in_str,in_substr); - while (str_look!=NULL) - { - cpt++; - str_look=strstr(str_look+l1,in_substr); - } - /* is there anything to do? */ - if (cpt) - { - /* we realloc to a size that will fit all replaces */ - out_str=MemRealloc(in_str,sl+1+dif*cpt); - str_look=strstr(out_str,in_substr); - while (str_look!=NULL && cpt) - { - /* as the replace string is bigger we - have to move memory first from the end */ - m1=out_str+sl; - m2=m1+dif; - sl+=dif; - while (m1!=str_look+l1-dif) - { - *m2=*m1; - m1--;m2--; - } - /* then we copy the replace string (can't be NULL in this case) */ - memcpy(str_look,out_substr,l2); - - /* look for next replace */ - if (!recurse) - str_look=strstr(str_look+l2,in_substr); - else - str_look=strstr(in_str,in_substr); - - /* to prevent from naughty overlap */ - cpt--; - } - if (str_look!=NULL) - { - printf("INTERNAL ERROR - overlapping replace string (%s/%s), you can't use this one!\n",in_substr,out_substr); - exit(ABORT_ERROR); - } - } - else - out_str=in_str; - } - return out_str; -} -#endif - -#ifndef min -#define min(a,b) \ - ({ __typeof__ (a) _a = (a); \ - __typeof__ (b) _b = (b); \ - _a < _b ? _a : _b; }) -#endif - -/* Levenshtein implementation by TheRayTracer https://gist.github.com/TheRayTracer/2644387 */ -int _internal_LevenshteinDistance(char *s, char *t) -{ - int i,j,n,m,*d; - int im,jn; - int r; - - n=strlen(s)+1; - m=strlen(t)+1; - d=malloc(n*m*sizeof(int)); - memset(d, 0, sizeof(int) * n * m); - - for (i = 1, im = 0; i < m; i++, im++) - { - for (j = 1, jn = 0; j < n; j++, jn++) - { - if (s[jn] == t[im]) - { - d[(i * n) + j] = d[((i - 1) * n) + (j - 1)]; - } - else - { - d[(i * n) + j] = min(d[(i - 1) * n + j] + 1, /* A deletion. */ - min(d[i * n + (j - 1)] + 1, /* An insertion. */ - d[(i - 1) * n + (j - 1)] + 1)); /* A substitution. */ - } - } - } - r = d[n * m - 1]; - free(d); - return r; -} - -#ifdef RASM_THREAD -/* - threads used for crunching -*/ -void _internal_ExecuteThreads(struct s_assenv *ae,struct s_rasm_thread *rasm_thread, void *(*fct)(void *)) -{ - #undef FUNC - #define FUNC "_internal_ExecuteThreads" - - pthread_attr_t attr; - void *status; - int rc; - /* launch threads */ - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE); - pthread_attr_setstacksize(&attr,65536); - - if ((rc=pthread_create(&image_threads[i].thread,&attr,fct,(void *)rasm_thread))) { - rasm_printf(ae,"FATAL ERROR - Cannot create thread!\n"); - exit(INTERNAL_ERROR); - } -} -void _internal_WaitForThreads(struct s_assenv *ae,struct s_rasm_thread *rasm_thread) -{ - #undef FUNC - #define FUNC "_internal_WaitForThreads" - int rc; - - if ((rc=pthread_join(rasm_thread->thread,&status))) { - rasm_printf(ae,"FATAL ERROR - Cannot wait for thread\n"); - exit(INTERNAL_ERROR); - } -} -void PushCrunchedFile(struct s_assenv *ae, unsigned char *datain, int datalen, int lz) -{ - #undef FUNC - #define FUNC "PushCrunchedFile" - - struct s_rasm_thread *rasm_thread; - - rasm_thread=MemMalloc(sizeof(struct s_rasm_thread)); - memset(rasm_thread,0,sizeof(struct s_rasm_thread)); - rasm_thread->datain=datain; - rasm_thread->datalen=datalen; - rasm_thread->lz=lz; - _internal_ExecuteThreads(ae,rasm_thread, void *(*fct)(void *)); - ObjectArrayAddDynamicValueConcat((void**)&ae->rasm_thread,&ae->irt,&ae->mrt,&rasm_thread,sizeof(struct s_rasm_thread *)); -} -void PopAllCrunchedFiles(struct s_assenv *ae) -{ - #undef FUNC - #define FUNC "PopAllCrunchedFiles" - - int i; - for (i=0;iirt;i++) { - _internal_WaitForThreads(ae,ae->rasm_thread[i]); - } -} -#endif - -void MaxError(struct s_assenv *ae); - -void rasm_printf(struct s_assenv *ae, ...) { - #undef FUNC - #define FUNC "(internal) rasm_printf" - - char *format; - va_list argptr; - - if (!ae->flux && !ae->dependencies) { - va_start(argptr,ae); - format=va_arg(argptr,char *); - vfprintf(stdout,format,argptr); - va_end(argptr); - fprintf(stdout,KNORMAL); - } -} -/*** - build the string of current line for error messages -*/ -char *rasm_getline(struct s_assenv *ae, int offset) { - #undef FUNC - #define FUNC "rasm_getline" - - static char myline[40]={0}; - int idx=0,icopy,first=1; - - while (!ae->wl[ae->idx+offset].t && idx<32) { - for (icopy=0;idx<32 && ae->wl[ae->idx+offset].w[icopy];icopy++) { - myline[idx++]=ae->wl[ae->idx+offset].w[icopy]; - } - if (!first) myline[idx++]=','; else first=0; - offset++; - } - if (idx>=32) { - strcpy(myline+29,"..."); - } else { - myline[idx++]=0; - } - - return myline; -} - -char *SimplifyPath(char *filename) { - #undef FUNC - #define FUNC "SimplifyPath" - - return filename; -#if 0 - char *pos,*repos; - int i,len; - - char *rpath; - - rpath=realpath(filename,NULL); - if (!rpath) { - printf("rpath error!\n"); - switch (errno) { - case EACCES:printf("read permission failure\n");break; - case EINVAL:printf("wrong argument\n");break; - case EIO:printf("I/O error\n");break; - case ELOOP:printf("too many symbolic links\n");break; - case ENAMETOOLONG:printf("names too long\n");break; - case ENOENT:printf("names does not exists\n");break; - case ENOMEM:printf("out of memory\n");break; - case ENOTDIR:printf("a component of the path is not a directory\n");break; - default:printf("unknown error\n");break; - } - exit(1); - } - if (strlen(rpath)=filename) { - if (*repos=='\\') { - break; - } - repos--; - } - repos++; - if (repos>=filename && repos!=pos) { - len=strlen(pos)-4+1; - pos+=4; - for (i=0;i=filename) { - if (*repos=='/') { - break; - } - repos--; - } - repos++; - if (repos>=filename && repos!=pos) { - len=strlen(pos)-4+1; - pos+=4; - for (i=0;i=0 && filename[idx]!='\\') idx--; - if (idx<0) { - /* pas de chemin */ - strcpy(curpath,".\\"); - } else { - /* chemin trouve */ - strcpy(curpath,filename); - curpath[idx+1]=0; - } -#else -#ifdef __MORPHOS__ - #define CURRENT_DIR "" -#else - #define CURRENT_DIR "./" -#endif - idx=zelen-1; - while (idx>=0 && filename[idx]!='/') idx--; - if (idx<0) { - /* pas de chemin */ - strcpy(curpath,CURRENT_DIR); - } else { - /* chemin trouve */ - strcpy(curpath,filename); - curpath[idx+1]=0; - } -#endif - - return curpath; -} -char *MergePath(struct s_assenv *ae,char *dadfilename, char *filename) { - #undef FUNC - #define FUNC "MergePath" - - static char curpath[PATH_MAX]; - int zelen; - -#ifdef OS_WIN - TxtReplace(filename,"/","\\",1); - - if (filename[0] && filename[1]==':' && filename[2]=='\\') { - /* chemin absolu */ - strcpy(curpath,filename); - } else if (filename[0] && filename[1]==':') { - rasm_printf(ae,KERROR"unsupported path style [%s]\n",filename); - exit(-111); - } else { - if (filename[0]=='.' && filename[1]=='\\') { - strcpy(curpath,GetPath(dadfilename)); - strcat(curpath,filename+2); - } else { - strcpy(curpath,GetPath(dadfilename)); - strcat(curpath,filename); - } - } -#else - if (filename[0]=='/') { - /* chemin absolu */ - strcpy(curpath,filename); - } else if (filename[0]=='.' && filename[1]=='/') { - strcpy(curpath,GetPath(dadfilename)); - strcat(curpath,filename+2); - } else { - strcpy(curpath,GetPath(dadfilename)); - strcat(curpath,filename); - } -#endif - - return curpath; -} - - -void InitAutomate(char *autotab, const unsigned char *def) -{ - #undef FUNC - #define FUNC "InitAutomate" - - int i; - - memset(autotab,0,256); - for (i=0;def[i];i++) { - autotab[(int)def[i]]=1; - } -} -void StateMachineResizeBuffer(char **ABuf, int idx, int *ASize) { - #undef FUNC - #define FUNC "StateMachineResizeBuffer" - - if (idx>=*ASize) { - if (*ASize<16384) { - *ASize=(*ASize)*2; - } else { - *ASize=(*ASize)+16384; - } - *ABuf=MemRealloc(*ABuf,(*ASize)+2); - } -} - -int GetCRC(char *label) -{ - #undef FUNC - #define FUNC "GetCRC" - int crc=0x12345678; - int i=0; - - while (label[i]!=0) { - crc=(crc<<9)^(crc+label[i++]); - } - return crc; -} - -int IsRegister(char *zeexpression) -{ - #undef FUNC - #define FUNC "IsRegister" - - switch (GetCRC(zeexpression)) { - case CRC_F:if (strcmp(zeexpression,"F")==0) return 1; else return 0; - case CRC_I:if (strcmp(zeexpression,"I")==0) return 1; else return 0; - case CRC_R:if (strcmp(zeexpression,"R")==0) return 1; else return 0; - case CRC_A:if (strcmp(zeexpression,"A")==0) return 1; else return 0; - case CRC_B:if (strcmp(zeexpression,"B")==0) return 1; else return 0; - case CRC_C:if (strcmp(zeexpression,"C")==0) return 1; else return 0; - case CRC_D:if (strcmp(zeexpression,"D")==0) return 1; else return 0; - case CRC_E:if (strcmp(zeexpression,"E")==0) return 1; else return 0; - case CRC_H:if (strcmp(zeexpression,"H")==0) return 1; else return 0; - case CRC_L:if (strcmp(zeexpression,"L")==0) return 1; else return 0; - case CRC_BC:if (strcmp(zeexpression,"BC")==0) return 1; else return 0; - case CRC_DE:if (strcmp(zeexpression,"DE")==0) return 1; else return 0; - case CRC_HL:if (strcmp(zeexpression,"HL")==0) return 1; else return 0; - case CRC_IX:if (strcmp(zeexpression,"IX")==0) return 1; else return 0; - case CRC_IY:if (strcmp(zeexpression,"IY")==0) return 1; else return 0; - case CRC_SP:if (strcmp(zeexpression,"SP")==0) return 1; else return 0; - case CRC_AF:if (strcmp(zeexpression,"AF")==0) return 1; else return 0; - case CRC_XH:if (strcmp(zeexpression,"XH")==0) return 1; else return 0; - case CRC_XL:if (strcmp(zeexpression,"XL")==0) return 1; else return 0; - case CRC_YH:if (strcmp(zeexpression,"YH")==0) return 1; else return 0; - case CRC_YL:if (strcmp(zeexpression,"YL")==0) return 1; else return 0; - case CRC_HX:if (strcmp(zeexpression,"HX")==0) return 1; else return 0; - case CRC_LX:if (strcmp(zeexpression,"LX")==0) return 1; else return 0; - case CRC_HY:if (strcmp(zeexpression,"HY")==0) return 1; else return 0; - case CRC_LY:if (strcmp(zeexpression,"LY")==0) return 1; else return 0; - case CRC_IXL:if (strcmp(zeexpression,"IXL")==0) return 1; else return 0; - case CRC_IXH:if (strcmp(zeexpression,"IXH")==0) return 1; else return 0; - case CRC_IYL:if (strcmp(zeexpression,"IYL")==0) return 1; else return 0; - case CRC_IYH:if (strcmp(zeexpression,"IYH")==0) return 1; else return 0; - default:break; - } - return 0; -} - -int StringIsMem(char *w) -{ - #undef FUNC - #define FUNC "StringIsMem" - - int p=1,idx=1; - - if (w[0]=='(') { - while (w[idx]) { - switch (w[idx]) { - case '\\':if (w[idx+1]) idx++; - break; - case '\'':if (w[idx+1] && w[idx+1]!='\\') idx++; - break; - case '(':p++;break; - case ')':p--; - if (!p && w[idx+1]) return 0; - break; - default:break; - } - idx++; - } - if (w[idx-1]!=')') return 0; - } else { - return 0; - } - return 1; - -} -int StringIsQuote(char *w) -{ - #undef FUNC - #define FUNC "StringIsQuote" - - int i,tquote,lens; - - if (w[0]=='\'' || w[0]=='"') { - tquote=w[0]; - lens=strlen(w); - - /* est-ce bien une chaine et uniquement une chaine? */ - i=1; - while (w[i] && w[i]!=tquote) { - if (w[i]=='\\') i++; - i++; - } - if (i==lens-1) { - return tquote; - } - } - return 0; -} -char *StringLooksLikeDicoRecurse(struct s_crcdico_tree *lt, int *score, char *str) -{ - #undef FUNC - #define FUNC "StringLooksLikeDicoRecurse" - - char *retstr=NULL,*tmpstr; - int i,curs; - - for (i=0;i<256;i++) { - if (lt->radix[i]) { - tmpstr=StringLooksLikeDicoRecurse(lt->radix[i],score,str); - if (tmpstr!=NULL) retstr=tmpstr; - } - } - if (lt->mdico) { - for (i=0;indico;i++) { - if (strlen(lt->dico[i].name)>4) { - curs=_internal_LevenshteinDistance(str,lt->dico[i].name); - if (curs<*score) { - *score=curs; - retstr=lt->dico[i].name; - } - } - } - } - return retstr; -} -char *StringLooksLikeDico(struct s_assenv *ae, int *score, char *str) -{ - #undef FUNC - #define FUNC "StringLooksLikeDico" - - char *retstr=NULL,*tmpstr; - int i; - - for (i=0;i<256;i++) { - if (ae->dicotree.radix[i]) { - tmpstr=StringLooksLikeDicoRecurse(ae->dicotree.radix[i],score,str); - if (tmpstr!=NULL) retstr=tmpstr; - } - } - return retstr; -} -char *StringLooksLikeMacro(struct s_assenv *ae, char *str, int *retscore) -{ - #undef FUNC - #define FUNC "StringLooksLikeMacro" - - char *ret=NULL; - int i,curs,score=3; - /* search in macros */ - for (i=0;iimacro;i++) { - curs=_internal_LevenshteinDistance(ae->macro[i].mnemo,str); - if (cursmacro[i].mnemo; - } - } - if (retscore) *retscore=score; - return ret; -} - -char *StringLooksLike(struct s_assenv *ae, char *str) -{ - #undef FUNC - #define FUNC "StringLooksLike" - - char *ret=NULL,*tmpret; - int i,curs,score=4; - - /* search in variables */ - ret=StringLooksLikeDico(ae,&score,str); - - /* search in labels */ - for (i=0;iil;i++) { - if (!ae->label[i].name && strlen(ae->wl[ae->label[i].iw].w)>4) { - curs=_internal_LevenshteinDistance(ae->wl[ae->label[i].iw].w,str); - if (curswl[ae->label[i].iw].w; - } - } - } - - /* search in alias */ - for (i=0;iialias;i++) { - if (strlen(ae->alias[i].alias)>4) { - curs=_internal_LevenshteinDistance(ae->alias[i].alias,str); - if (cursalias[i].alias; - } - } - } - - tmpret=StringLooksLikeMacro(ae,str,&curs); - if (cursflux) { - /* in embedded Rasm all errors are stored in a debug struct */ - struct s_debug_error curerror; - char toosmalltotakeitall[2]={0}; - int myalloc; - char *errstr; - - va_start(argptr,format); - myalloc=vsnprintf(toosmalltotakeitall,1,format,argptr); - va_end(argptr); - - #if defined(_MSC_VER) && _MSC_VER < 1900 - /* visual studio before 2015 does not fully support C99 */ - if (myalloc<1 && strlen(format)) { - va_start(argptr,format); - myalloc=_vscprintf(format,argptr); - va_end(argptr); - } - #endif - if (myalloc<1) { - /* do not crash */ - return; - } - - va_start(argptr,format); - errstr=MemMalloc(myalloc+1); - vsnprintf(errstr,myalloc,format,argptr); - curerror.msg=errstr; - curerror.lenmsg=myalloc; - curerror.line=line; - if (filename) curerror.filename=TxtStrDupLen(filename,&curerror.lenfilename); else curerror.filename=TxtStrDupLen("",&curerror.lenfilename); - ObjectArrayAddDynamicValueConcat((void **)&ae->debug.error,&ae->debug.nberror,&ae->debug.maxerror,&curerror,sizeof(struct s_debug_error)); - va_end(argptr); - } else { - fprintf(stdout,KERROR); - va_start(argptr,format); - if (filename && line) { - printf("[%s:%d] ",filename,line); - } else if (filename) { - printf("[%s] ",filename); - } - vfprintf(stdout,format,argptr); - va_end(argptr); - fprintf(stdout,KNORMAL); - } -} - - -/* convert v double value to Amstrad REAL */ -unsigned char *__internal_MakeAmsdosREAL(struct s_assenv *ae, double v, int iexpression) -{ - #undef FUNC - #define FUNC "__internal_MakeAmsdosREAL" - - static unsigned char rc[5]; - - double tmpval; - int j,ib,ibb,exp=0; - unsigned int deci; - int fracmax=0; - double frac; - int mesbits[32]; - int ibit=0; - unsigned int mask; - - memset(rc,0,sizeof(rc)); - - deci=fabs(floor(v)); - frac=fabs(v)-deci; - - if (deci) { - mask=0x80000000; - while (!(deci & mask)) mask=mask/2; - while (mask) { - mesbits[ibit]=!!(deci & mask); -#if TRACE_MAKEAMSDOSREAL -printf("%d",mesbits[ibit]); -#endif - ibit++; - mask=mask/2; - } -#if TRACE_MAKEAMSDOSREAL -printf("\nexposant positif: %d\n",ibit); -#endif - exp=ibit; -#if TRACE_MAKEAMSDOSREAL -printf("."); -#endif - while (ibit<32 && frac!=0) { - frac=frac*2; - if (frac>=1.0) { - mesbits[ibit++]=1; -#if TRACE_MAKEAMSDOSREAL -printf("1"); -#endif - frac-=1.0; - } else { - mesbits[ibit++]=0; -#if TRACE_MAKEAMSDOSREAL -printf("0"); -#endif - } - fracmax++; - } - } else { -#if TRACE_MAKEAMSDOSREAL -printf("\nexposant negatif a definir:\n"); -printf("x."); -#endif - - /* handling zero */ - if (frac==0.0) { - exp=0; - ibit=0; - } else { - /* looking for first significant bit */ - while (1) { - frac=frac*2; - if (frac>=1.0) { - mesbits[ibit++]=1; -#if TRACE_MAKEAMSDOSREAL -printf("1"); -#endif - frac-=1.0; - break; /* first significant bit found, now looking for limit */ - } else { -#if TRACE_MAKEAMSDOSREAL -printf("o"); -#endif - } - fracmax++; - exp--; - } - while (ibit<32 && frac!=0) { - frac=frac*2; - if (frac>=1.0) { - mesbits[ibit++]=1; -#if TRACE_MAKEAMSDOSREAL -printf("1"); -#endif - frac-=1.0; - } else { - mesbits[ibit++]=0; -#if TRACE_MAKEAMSDOSREAL -printf("0"); -#endif - } - fracmax++; - } - } - } - -#if TRACE_MAKEAMSDOSREAL -printf("\n%d bits utilises en mantisse\n",ibit); -#endif - /* pack bits */ - ib=3;ibb=0x80; - for (j=0;j255) { - if (iexpression) MakeError(ae,GetExpFile(ae,iexpression),ae->wl[ae->expression[iexpression].iw].l,"Exponent overflow\n"); - else MakeError(ae,GetExpFile(ae,0),ae->wl[ae->idx].l,"Exponent overflow\n"); - exp=128; - } - rc[4]=exp; - - /* REAL sign */ - if (v>=0) { - rc[3]&=0x7F; - } else { - rc[3]|=0x80; - } - -#if TRACE_MAKEAMSDOSREAL - for (j=0;j<5;j++) printf("%02X ",rc[j]); - printf("\n"); -#endif - - return rc; -} - - - - -struct s_label *SearchLabel(struct s_assenv *ae, char *label, int crc); -char *GetExpFile(struct s_assenv *ae,int didx){ - #undef FUNC - #define FUNC "GetExpFile" - - if (ae->label_filename) { - return ae->label_filename; - } - if (didx<0) { - return ae->filename[ae->wl[-didx].ifile]; - } else if (!didx) { - return ae->filename[ae->wl[ae->idx].ifile]; - } else if (ae->expression && didxie) { - return ae->filename[ae->wl[ae->expression[didx].iw].ifile]; - } else { - //return ae->filename[ae->wl[ae->idx].ifile]; - return 0; - } -} - -int GetExpLine(struct s_assenv *ae,int didx){ - #undef FUNC - #define FUNC "GetExpLine" - - if (ae->label_line) return ae->label_line; - - if (didx<0) { - return ae->wl[-didx].l; - } else if (!didx) { - return ae->wl[ae->idx].l; - } else if (didxie) { - return ae->wl[ae->expression[didx].iw].l; - } else return 0; -} - -char *GetCurrentFile(struct s_assenv *ae) -{ - return GetExpFile(ae,0); -} - - -/******************************************************************************************* - M E M O R Y C L E A N U P -*******************************************************************************************/ -void FreeLabelTree(struct s_assenv *ae); -void FreeDicoTree(struct s_assenv *ae); -void FreeUsedTree(struct s_assenv *ae); -void ExpressionFastTranslate(struct s_assenv *ae, char **ptr_expr, int fullreplace); -char *TradExpression(char *zexp); - - -void _internal_RasmFreeInfoStruct(struct s_rasm_info *debug) -{ - #undef FUNC - #define FUNC "RasmFreeInfoStruct" - - int i; - if (debug->maxerror) { - for (i=0;inberror;i++) { - MemFree(debug->error[i].filename); - MemFree(debug->error[i].msg); - } - MemFree(debug->error); - } - if (debug->maxsymbol) { - for (i=0;inbsymbol;i++) { - MemFree(debug->symbol[i].name); - } - MemFree(debug->symbol); - } -} - -void RasmFreeInfoStruct(struct s_rasm_info *debug) -{ - _internal_RasmFreeInfoStruct(debug); - MemFree(debug); -} - -void FreeAssenv(struct s_assenv *ae) -{ - #undef FUNC - #define FUNC "FreeAssenv" - int i,j; - -#ifndef RDD - /* let the system free the memory in command line except when debug/dev */ - if (!ae->flux) return; -#endif - /*** debug info ***/ - if (!ae->retdebug) { - _internal_RasmFreeInfoStruct(&ae->debug); - } else { - /* symbols */ - struct s_debug_symbol debug_symbol={0}; - - for (i=0;iil;i++) { - /* on exporte tout */ - if (!ae->label[i].name) { - /* les labels entiers */ - debug_symbol.name=TxtStrDup(ae->wl[ae->label[i].iw].w); - debug_symbol.v=ae->label[i].ptr; - ObjectArrayAddDynamicValueConcat((void**)&ae->debug.symbol,&ae->debug.nbsymbol,&ae->debug.maxsymbol,&debug_symbol,sizeof(struct s_debug_symbol)); - } else { - /* les labels locaux et générés */ - debug_symbol.name=TxtStrDup(ae->label[i].name); - debug_symbol.v=ae->label[i].ptr; - ObjectArrayAddDynamicValueConcat((void**)&ae->debug.symbol,&ae->debug.nbsymbol,&ae->debug.maxsymbol,&debug_symbol,sizeof(struct s_debug_symbol)); - } - } - for (i=0;iialias;i++) { - if (strcmp(ae->alias[i].alias,"IX") && strcmp(ae->alias[i].alias,"IY")) { - debug_symbol.name=TxtStrDup(ae->alias[i].alias); - debug_symbol.v=RoundComputeExpression(ae,ae->alias[i].translation,0,0,0); - ObjectArrayAddDynamicValueConcat((void**)&ae->debug.symbol,&ae->debug.nbsymbol,&ae->debug.maxsymbol,&debug_symbol,sizeof(struct s_debug_symbol)); - } - } - - /* export struct */ - *ae->retdebug=MemMalloc(sizeof(struct s_rasm_info)); - memcpy(*ae->retdebug,&ae->debug,sizeof(struct s_rasm_info)); - } - /*** end debug ***/ - - for (i=0;inbbank;i++) { - MemFree(ae->mem[i]); - } - MemFree(ae->mem); - - /* expression core buffer free */ - ComputeExpressionCore(NULL,NULL,0,0); - ExpressionFastTranslate(NULL,NULL,0); - /* free labels, expression, orgzone, repeat, ... */ - if (ae->mo) MemFree(ae->orgzone); - if (ae->me) { - for (i=0;iie;i++) if (ae->expression[i].reference) MemFree(ae->expression[i].reference); - MemFree(ae->expression); - } - if (ae->mh) { - for (i=0;iih;i++) { - MemFree(ae->hexbin[i].data); - MemFree(ae->hexbin[i].filename); - } - MemFree(ae->hexbin); - } - for (i=0;iil;i++) { - if (ae->label[i].name && ae->label[i].iw==-1) MemFree(ae->label[i].name); - } - /* structures */ - for (i=0;iirasmstructalias;i++) { - MemFree(ae->rasmstructalias[i].name); - } - if (ae->mrasmstructalias) MemFree(ae->rasmstructalias); - - for (i=0;iirasmstruct;i++) { - for (j=0;jrasmstruct[i].irasmstructfield;j++) { - MemFree(ae->rasmstruct[i].rasmstructfield[j].fullname); - MemFree(ae->rasmstruct[i].rasmstructfield[j].name); - } - if (ae->rasmstruct[i].mrasmstructfield) MemFree(ae->rasmstruct[i].rasmstructfield); - MemFree(ae->rasmstruct[i].name); - } - if (ae->mrasmstruct) MemFree(ae->rasmstruct); - - /* other */ - if (ae->maxbreakpoint) MemFree(ae->breakpoint); - if (ae->ml) MemFree(ae->label); - if (ae->mr) MemFree(ae->repeat); - if (ae->mi) MemFree(ae->ifthen); - if (ae->msw) MemFree(ae->switchcase); - if (ae->mw) MemFree(ae->whilewend); - if (ae->modulen || ae->module) { - MemFree(ae->module); - } - /* deprecated - for (i=0;iidic;i++) { - MemFree(ae->dico[i].name); - } - if (ae->mdic) MemFree(ae->dico); - */ - if (ae->mlz) MemFree(ae->lzsection); - - for (i=0;iifile;i++) { - MemFree(ae->filename[i]); - } - MemFree(ae->filename); - - for (i=0;iimacro;i++) { - if (ae->macro[i].maxword) MemFree(ae->macro[i].wc); - for (j=0;jmacro[i].nbparam;j++) MemFree(ae->macro[i].param[j]); - if (ae->macro[i].nbparam) MemFree(ae->macro[i].param); - } - - - if (ae->mmacro) MemFree(ae->macro); - - for (i=0;iialias;i++) { - MemFree(ae->alias[i].alias); - MemFree(ae->alias[i].translation); - } - if (ae->malias) MemFree(ae->alias); - - for (i=0;ae->wl[i].t!=2;i++) { - MemFree(ae->wl[i].w); - } - MemFree(ae->wl); - - if (ae->ctx1.varbuffer) { - MemFree(ae->ctx1.varbuffer); - } - if (ae->ctx1.maxtokenstack) { - MemFree(ae->ctx1.tokenstack); - } - if (ae->ctx1.maxoperatorstack) { - MemFree(ae->ctx1.operatorstack); - } - if (ae->ctx2.varbuffer) { - MemFree(ae->ctx2.varbuffer); - } - if (ae->ctx2.maxtokenstack) { - MemFree(ae->ctx2.tokenstack); - } - if (ae->ctx2.maxoperatorstack) { - MemFree(ae->ctx2.operatorstack); - } - - for (i=0;iiticker;i++) { - MemFree(ae->ticker[i].varname); - } - if (ae->mticker) MemFree(ae->ticker); - - MemFree(ae->outputfilename); - FreeLabelTree(ae); - FreeDicoTree(ae); - FreeUsedTree(ae); - if (ae->mmacropos) MemFree(ae->macropos); - TradExpression(NULL); - MemFree(ae); -} - - - -void MaxError(struct s_assenv *ae) -{ - #undef FUNC - #define FUNC "MaxError" - - char **source_lines=NULL; - int idx,crc,zeline; - char c; - - /* extended error is useful with generated code we do not want to edit */ - if (ae->extended_error && ae->wl) { - /* super dupper slow but anyway, there is an error... */ - if (ae->wl[ae->idx].l) { - source_lines=FileReadLinesRAW(GetCurrentFile(ae)); - zeline=0; - while (zelinewl[ae->idx].l-1 && source_lines[zeline]) zeline++; - if (zeline==ae->wl[ae->idx].l-1 && source_lines[zeline]) { - rasm_printf(ae,KAYGREEN"-> %s",source_lines[zeline]); - } else { - rasm_printf(ae,KERROR"cannot read line %d of file [%s]\n",ae->wl[ae->idx].l,GetCurrentFile(ae)); - } - FreeArrayDynamicValue(&source_lines); - } - } - - ae->nberr++; - if (ae->nberr==ae->maxerr) { - rasm_printf(ae,KERROR"Too many errors!\n"); - FreeAssenv(ae); - exit(ae->nberr); - } -} - -void (*___output)(struct s_assenv *ae, unsigned char v); - -void ___internal_output_disabled(struct s_assenv *ae,unsigned char v) -{ - #undef FUNC - #define FUNC "fake ___output" -} -void ___internal_output(struct s_assenv *ae,unsigned char v) -{ - #undef FUNC - #define FUNC "___output" - - if (ae->outputadrmaxptr) { - ae->mem[ae->activebank][ae->outputadr++]=v; - ae->codeadr++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"output exceed limit %d\n",ae->maxptr); - ae->stop=1; - ___output=___internal_output_disabled; - } -} -void ___internal_output_nocode(struct s_assenv *ae,unsigned char v) -{ - #undef FUNC - #define FUNC "___output (nocode)" - - if (ae->outputadrmaxptr) { - /* struct definition always in NOCODE */ - if (ae->getstruct) { - int irs,irsf; - irs=ae->irasmstruct-1; - irsf=ae->rasmstruct[irs].irasmstructfield-1; - - /* ajouter les data du flux au champ de la structure */ - ObjectArrayAddDynamicValueConcat((void**)&ae->rasmstruct[irs].rasmstructfield[irsf].data, - &ae->rasmstruct[irs].rasmstructfield[irsf].idata, - &ae->rasmstruct[irs].rasmstructfield[irsf].mdata, - &v,sizeof(unsigned char)); - } - - ae->outputadr++; - ae->codeadr++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"output exceed limit %d\n",ae->maxptr); - ae->stop=1; - ___output=___internal_output_disabled; - } -} - - -void ___output_set_limit(struct s_assenv *ae,int zelimit) -{ - #undef FUNC - #define FUNC "___output_set_limit" - - int limit=65535; - - if (zelimit<=limit) { - /* apply limit */ - limit=zelimit; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"limit exceed hardware limitation!"); - ae->stop=1; - } - if (ae->outputadr>=0 && ae->outputadr>limit) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"limit too high for current output!"); - ae->stop=1; - } - ae->maxptr=limit; -} - -unsigned char *MakeAMSDOSHeader(int run, int minmem, int maxmem, char *amsdos_name) { - #undef FUNC - #define FUNC "MakeAMSDOSHeader" - - static unsigned char AmsdosHeader[128]; - int checksum,i=0; - /*** cpcwiki - Byte 00: User number - Byte 01 to 08: filename - Byte 09 bis 11: Extension - Byte 18: type-byte - Byte 21 and 22: loading address - Byte 24 and 25: file length - Byte 26 and 27: execution address for machine code programs - Byte 64 and 65: (file length) - Byte 67 and 68: checksum for byte 00 to byte 66 - To calculate the checksum, just add byte 00 to byte 66 to each other. - */ - memset(AmsdosHeader,0,sizeof(AmsdosHeader)); - AmsdosHeader[0]=0; - memcpy(AmsdosHeader+1,amsdos_name,11); - - AmsdosHeader[18]=2; /* 0 basic 1 basic protege 2 binaire */ - AmsdosHeader[19]=(maxmem-minmem)&0xFF; - AmsdosHeader[20]=(maxmem-minmem)>>8; - AmsdosHeader[21]=minmem&0xFF; - AmsdosHeader[22]=minmem>>8; - AmsdosHeader[24]=AmsdosHeader[19]; - AmsdosHeader[25]=AmsdosHeader[20]; - AmsdosHeader[26]=run&0xFF; - AmsdosHeader[27]=run>>8; - AmsdosHeader[64]=AmsdosHeader[19]; - AmsdosHeader[65]=AmsdosHeader[20]; - AmsdosHeader[66]=0; - - for (i=checksum=0;i<=66;i++) { - checksum+=AmsdosHeader[i]; - } - AmsdosHeader[67]=checksum&0xFF; - AmsdosHeader[68]=checksum>>8; - - /* garbage / shadow values from sector buffer? */ - memcpy(AmsdosHeader+0x47,amsdos_name,8); - AmsdosHeader[0x4F]=0x24; - AmsdosHeader[0x50]=0x24; - AmsdosHeader[0x51]=0x24; - AmsdosHeader[0x52]=0xFF; - AmsdosHeader[0x54]=0xFF; - AmsdosHeader[0x57]=0x02; - AmsdosHeader[0x5A]=AmsdosHeader[21]; - AmsdosHeader[0x5B]=AmsdosHeader[22]; - AmsdosHeader[0x5D]=AmsdosHeader[24]; - AmsdosHeader[0x5E]=AmsdosHeader[25]; - - sprintf((char *)AmsdosHeader+0x47+17," generated by %s ",RASM_SNAP_VERSION); - - return AmsdosHeader; -} - -unsigned char *MakeHobetaHeader(int minmem, int maxmem, char *trdos_name) { - #undef FUNC - #define FUNC "MakeHobetaHeader" - - static unsigned char HobetaHeader[17]; - int i,checksum=0; - /*** http://rk.nvg.ntnu.no/sinclair/faq/fileform.html#HOBETA - 0x00 FileName 0x08 TR-DOS file name - 0x08 FileType 0x01 TR-DOS file type - 0x09 StartAdr 0x02 start address of file - 0x0A FlLength 0x02 length of file (in bytes) -> /!\ wrong offset!!! - 0x0C FileSize 0x02 size of file (in sectors) - 0x0E HdrCRC16 0x02 Control checksum of the 15 byte - header (not sector data!) - */ - memset(HobetaHeader,0,sizeof(HobetaHeader)); - - strncpy(HobetaHeader,trdos_name,8); - HobetaHeader[8]='C'; - HobetaHeader[0x9]=(maxmem-minmem)&0xFF; - HobetaHeader[0xA]=(maxmem-minmem)>>8; - - HobetaHeader[0xB]=(maxmem-minmem)&0xFF; - HobetaHeader[0xC]=(maxmem-minmem)>>8; - - HobetaHeader[0xD]=((maxmem-minmem)+255)>>8; - HobetaHeader[0xE]=0; - - for (i=0;i<0xF;i++) checksum+=HobetaHeader[i]*257+i; - - HobetaHeader[0xF]=checksum&0xFF; - HobetaHeader[0x10]=(checksum>>8)&0xFF; - - return HobetaHeader; -} - - -int cmpAmsdosentry(const void * a, const void * b) -{ - return memcmp(a,b,32); -} - -int cmpmacros(const void * a, const void * b) -{ - struct s_macro *sa,*sb; - sa=(struct s_macro *)a; - sb=(struct s_macro *)b; - if (sa->crccrc) return -1; else return 1; -} -int SearchAlias(struct s_assenv *ae, int crc, char *zemot) -{ - int dw,dm,du,i; -//printf("SearchAlias [%s] ",zemot); - /* inutile de tourner autour du pot pour un si petit nombre */ - if (ae->ialias<5) { - for (i=0;iialias;i++) { - if (ae->alias[i].crc==crc && strcmp(ae->alias[i].alias,zemot)==0) { - ae->alias[i].used=1; -//printf("found\n"); - return i; - } - } -//printf("not found\n"); - return -1; - } - - dw=0; - du=ae->ialias-1; - while (dw<=du) { - dm=(dw+du)/2; - if (ae->alias[dm].crc==crc) { - /* chercher le premier de la liste */ - while (dm>0 && ae->alias[dm-1].crc==crc) dm--; - /* controle sur le texte entier */ - while (ae->alias[dm].crc==crc && strcmp(ae->alias[dm].alias,zemot)) dm++; - if (ae->alias[dm].crc==crc && strcmp(ae->alias[dm].alias,zemot)==0) { - ae->alias[dm].used=1; -//printf("found\n"); - return dm; - } else return -1; - } else if (ae->alias[dm].crc>crc) { - du=dm-1; - } else if (ae->alias[dm].crcimacro<5) { - for (i=0;iimacro;i++) { - if (ae->macro[i].crc==crc && strcmp(ae->macro[i].mnemo,zemot)==0) { - return i; - } - } - return -1; - } - - dw=0; - du=ae->imacro-1; - while (dw<=du) { - dm=(dw+du)/2; - if (ae->macro[dm].crc==crc) { - /* chercher le premier de la liste */ - while (dm>0 && ae->macro[dm-1].crc==crc) dm--; - /* controle sur le texte entier */ - while (ae->macro[dm].crc==crc && strcmp(ae->macro[dm].mnemo,zemot)) dm++; - if (ae->macro[dm].crc==crc && strcmp(ae->macro[dm].mnemo,zemot)==0) return dm; else return -1; - } else if (ae->macro[dm].crc>crc) { - du=dm-1; - } else if (ae->macro[dm].crcialias-1;i++) { - /* is there previous aliases in the new alias? */ - if (strstr(ae->alias[ae->ialias-1].translation,ae->alias[i].alias)) { - /* there is a match, apply alias translation */ - ExpressionFastTranslate(ae,&ae->alias[ae->ialias-1].translation,2); - /* need to compute again len */ - ae->alias[ae->ialias-1].len=strlen(ae->alias[ae->ialias-1].translation); - break; - } - } - - /* cas particuliers pour insertion en début ou fin de liste */ - if (ae->ialias-1) { - if (ae->alias[ae->ialias-1].crc>ae->alias[ae->ialias-2].crc) { - /* pas de tri il est déjà au bon endroit */ - } else if (ae->alias[ae->ialias-1].crcalias[0].crc) { - /* insertion tout en bas de liste */ - tmpalias=ae->alias[ae->ialias-1]; - MemMove(&ae->alias[1],&ae->alias[0],sizeof(struct s_alias)*(ae->ialias-1)); - ae->alias[0]=tmpalias; - } else { - /* on cherche ou inserer */ - crc=ae->alias[ae->ialias-1].crc; - dw=0; - du=ae->ialias-1; - while (dw<=du) { - dm=(dw+du)/2; - if (ae->alias[dm].crc==crc) { - break; - } else if (ae->alias[dm].crc>crc) { - du=dm-1; - } else if (ae->alias[dm].crcalias[dm].crcalias[ae->ialias-1]; - MemMove(&ae->alias[dm+1],&ae->alias[dm],sizeof(struct s_alias)*(ae->ialias-1-dm)); - ae->alias[dm]=tmpalias; - } - } else { - /* one alias need no sort */ - } -} - -void InsertDicoToTree(struct s_assenv *ae, struct s_expr_dico *dico) -{ - #undef FUNC - #define FUNC "InsertDicoToTree" - - struct s_crcdico_tree *curdicotree; - int radix,dek=32; - - curdicotree=&ae->dicotree; - while (dek) { - dek=dek-8; - radix=(dico->crc>>dek)&0xFF; - if (curdicotree->radix[radix]) { - curdicotree=curdicotree->radix[radix]; - } else { - curdicotree->radix[radix]=MemMalloc(sizeof(struct s_crcdico_tree)); - curdicotree=curdicotree->radix[radix]; - memset(curdicotree,0,sizeof(struct s_crcdico_tree)); - } - } - ObjectArrayAddDynamicValueConcat((void**)&curdicotree->dico,&curdicotree->ndico,&curdicotree->mdico,dico,sizeof(struct s_expr_dico)); -} - -unsigned char *SnapshotDicoInsert(char *symbol_name, int ptr, int *retidx) -{ - static unsigned char *subchunk=NULL; - static int subchunksize=0; - static int idx=0; - int symbol_len; - - if (retidx) { - if (symbol_name && strcmp(symbol_name,"FREE")==0) { - subchunksize=0; - idx=0; - MemFree(subchunk); - subchunk=NULL; - } - *retidx=idx; - return subchunk; - } - - if (idx+65536>subchunksize) { - subchunksize=subchunksize+65536; - subchunk=MemRealloc(subchunk,subchunksize); - } - - symbol_len=strlen(symbol_name); - if (symbol_len>255) symbol_len=255; - subchunk[idx++]=symbol_len; - memcpy(subchunk+idx,symbol_name,symbol_len); - idx+=symbol_len; - memset(subchunk+idx,0,6); - idx+=6; - subchunk[idx++]=(ptr&0xFF00)/256; - subchunk[idx++]=ptr&0xFF; - return NULL; -} - -void SnapshotDicoTreeRecurse(struct s_crcdico_tree *lt) -{ - #undef FUNC - #define FUNC "SnapshottDicoTreeRecurse" - - int i; - - for (i=0;i<256;i++) { - if (lt->radix[i]) { - SnapshotDicoTreeRecurse(lt->radix[i]); - } - } - if (lt->mdico) { - for (i=0;indico;i++) { - if (strcmp(lt->dico[i].name,"IX") && strcmp(lt->dico[i].name,"IY") && strcmp(lt->dico[i].name,"PI") && strcmp(lt->dico[i].name,"ASSEMBLER_RASM")) { - SnapshotDicoInsert(lt->dico[i].name,(int)floor(lt->dico[i].v+0.5),NULL); - } - } - } -} -unsigned char *SnapshotDicoTree(struct s_assenv *ae, int *retidx) -{ - #undef FUNC - #define FUNC "SnapshotDicoTree" - - unsigned char *sc; - int idx; - int i; - - for (i=0;i<256;i++) { - if (ae->dicotree.radix[i]) { - SnapshotDicoTreeRecurse(ae->dicotree.radix[i]); - } - } - - sc=SnapshotDicoInsert(NULL,0,&idx); - *retidx=idx; - return sc; -} - -void WarnLabelTreeRecurse(struct s_assenv *ae, struct s_crclabel_tree *lt) -{ - #undef FUNC - #define FUNC "WarnLabelTreeRecurse" - - int i; - - for (i=0;i<256;i++) { - if (lt->radix[i]) { - WarnLabelTreeRecurse(ae,lt->radix[i]); - } - } - for (i=0;inlabel;i++) { - if (!lt->label[i].used) { - if (!lt->label[i].name) { - rasm_printf(ae,KWARNING"[%s:%d] Warning: label %s declared but not used\n",ae->filename[lt->label[i].fileidx],lt->label[i].fileline,ae->wl[lt->label[i].iw].w); - } else { - rasm_printf(ae,KWARNING"[%s:%d] Warning: label %s declared but not used\n",ae->filename[lt->label[i].fileidx],lt->label[i].fileline,lt->label[i].name); - } - } - } -} -void WarnLabelTree(struct s_assenv *ae) -{ - #undef FUNC - #define FUNC "WarnLabelTree" - - int i; - - for (i=0;i<256;i++) { - if (ae->labeltree.radix[i]) { - WarnLabelTreeRecurse(ae,ae->labeltree.radix[i]); - } - } -} -void WarnDicoTreeRecurse(struct s_assenv *ae, struct s_crcdico_tree *lt) -{ - #undef FUNC - #define FUNC "WarnDicoTreeRecurse" - - char symbol_line[1024]; - int i; - - for (i=0;i<256;i++) { - if (lt->radix[i]) { - WarnDicoTreeRecurse(ae,lt->radix[i]); - } - } - for (i=0;indico;i++) { - if (strcmp(lt->dico[i].name,"IX") && strcmp(lt->dico[i].name,"IY") && strcmp(lt->dico[i].name,"PI") && strcmp(lt->dico[i].name,"ASSEMBLER_RASM") && lt->dico[i].autorise_export) { - rasm_printf(ae,KWARNING"[%s:%d] Warning: variable %s declared but not used\n",ae->filename[ae->wl[lt->dico[i].iw].ifile],ae->wl[lt->dico[i].iw].l,lt->dico[i].name); - } - } -} -void WarnDicoTree(struct s_assenv *ae) -{ - #undef FUNC - #define FUNC "ExportDicoTree" - - int i; - - for (i=0;i<256;i++) { - if (ae->dicotree.radix[i]) { - WarnDicoTreeRecurse(ae,ae->dicotree.radix[i]); - } - } -} -void ExportDicoTreeRecurse(struct s_crcdico_tree *lt, char *zefile, char *zeformat) -{ - #undef FUNC - #define FUNC "ExportDicoTreeRecurse" - - char symbol_line[1024]; - int i; - - for (i=0;i<256;i++) { - if (lt->radix[i]) { - ExportDicoTreeRecurse(lt->radix[i],zefile,zeformat); - } - } - if (lt->mdico) { - for (i=0;indico;i++) { - if (strcmp(lt->dico[i].name,"IX") && strcmp(lt->dico[i].name,"IY") && strcmp(lt->dico[i].name,"PI") && strcmp(lt->dico[i].name,"ASSEMBLER_RASM") && lt->dico[i].autorise_export) { - snprintf(symbol_line,sizeof(symbol_line)-1,zeformat,lt->dico[i].name,(int)floor(lt->dico[i].v+0.5)); - symbol_line[sizeof(symbol_line)-1]=0xD; - FileWriteLine(zefile,symbol_line); - } - } - } -} -void ExportDicoTree(struct s_assenv *ae, char *zefile, char *zeformat) -{ - #undef FUNC - #define FUNC "ExportDicoTree" - - int i; - - for (i=0;i<256;i++) { - if (ae->dicotree.radix[i]) { - ExportDicoTreeRecurse(ae->dicotree.radix[i],zefile,zeformat); - } - } -} -void FreeDicoTreeRecurse(struct s_crcdico_tree *lt) -{ - #undef FUNC - #define FUNC "FreeDicoTreeRecurse" - - int i; - - for (i=0;i<256;i++) { - if (lt->radix[i]) { - FreeDicoTreeRecurse(lt->radix[i]); - } - } - if (lt->mdico) { - for (i=0;indico;i++) { - MemFree(lt->dico[i].name); - } - MemFree(lt->dico); - } - MemFree(lt); -} -void FreeDicoTree(struct s_assenv *ae) -{ - #undef FUNC - #define FUNC "FreeDicoTree" - - int i; - - for (i=0;i<256;i++) { - if (ae->dicotree.radix[i]) { - FreeDicoTreeRecurse(ae->dicotree.radix[i]); - } - } - if (ae->dicotree.mdico) { - for (i=0;idicotree.ndico;i++) MemFree(ae->dicotree.dico[i].name); - MemFree(ae->dicotree.dico); - } -} -struct s_expr_dico *SearchDico(struct s_assenv *ae, char *dico, int crc) -{ - #undef FUNC - #define FUNC "SearchDico" - - struct s_crcdico_tree *curdicotree; - struct s_expr_dico *retdico=NULL; - int i,radix,dek=32; - - curdicotree=&ae->dicotree; - - while (dek) { - dek=dek-8; - radix=(crc>>dek)&0xFF; - if (curdicotree->radix[radix]) { - curdicotree=curdicotree->radix[radix]; - } else { - /* radix not found, dico is not in index */ - return NULL; - } - } - for (i=0;indico;i++) { - if (strcmp(curdicotree->dico[i].name,dico)==0) { - curdicotree->dico[i].used=1; - return &curdicotree->dico[i]; - } - } - return NULL; -} -int DelDico(struct s_assenv *ae, char *dico, int crc) -{ - #undef FUNC - #define FUNC "DelDico" - - struct s_crcdico_tree *curdicotree; - struct s_expr_dico *retdico=NULL; - int i,radix,dek=32; - - curdicotree=&ae->dicotree; - - while (dek) { - dek=dek-8; - radix=(crc>>dek)&0xFF; - if (curdicotree->radix[radix]) { - curdicotree=curdicotree->radix[radix]; - } else { - /* radix not found, dico is not in index */ - return 0; - } - } - for (i=0;indico;i++) { - if (strcmp(curdicotree->dico[i].name,dico)==0) { - /* must free memory */ - MemFree(curdicotree->dico[i].name); - if (indico-1) { - MemMove(&curdicotree->dico[i],&curdicotree->dico[i+1],(curdicotree->ndico-i-1)*sizeof(struct s_expr_dico)); - } - curdicotree->ndico--; - return 1; - } - } - return 0; -} - - -void InsertUsedToTree(struct s_assenv *ae, char *used, int crc) -{ - #undef FUNC - #define FUNC "InsertUsedToTree" - - struct s_crcused_tree *curusedtree; - int radix,dek=32,i; - - curusedtree=&ae->usedtree; - while (dek) { - dek=dek-8; - radix=(crc>>dek)&0xFF; - if (curusedtree->radix[radix]) { - curusedtree=curusedtree->radix[radix]; - } else { - curusedtree->radix[radix]=MemMalloc(sizeof(struct s_crcused_tree)); - curusedtree=curusedtree->radix[radix]; - memset(curusedtree,0,sizeof(struct s_crcused_tree)); - } - } - for (i=0;inused;i++) if (strcmp(used,curusedtree->used[i])==0) break; - /* no double */ - if (i==curusedtree->nused) { - FieldArrayAddDynamicValueConcat(&curusedtree->used,&curusedtree->nused,&curusedtree->mused,used); - } -} - -void FreeUsedTreeRecurse(struct s_crcused_tree *lt) -{ - #undef FUNC - #define FUNC "FreeUsedTreeRecurse" - - int i; - - for (i=0;i<256;i++) { - if (lt->radix[i]) { - FreeUsedTreeRecurse(lt->radix[i]); - } - } - if (lt->mused) { - for (i=0;inused;i++) MemFree(lt->used[i]); - MemFree(lt->used); - } - MemFree(lt); -} -void FreeUsedTree(struct s_assenv *ae) -{ - #undef FUNC - #define FUNC "FreeUsedTree" - - int i; - - for (i=0;i<256;i++) { - if (ae->usedtree.radix[i]) { - FreeUsedTreeRecurse(ae->usedtree.radix[i]); - } - } -} -int SearchUsed(struct s_assenv *ae, char *used, int crc) -{ - #undef FUNC - #define FUNC "SearchUsed" - - struct s_crcused_tree *curusedtree; - int i,radix,dek=32; - - curusedtree=&ae->usedtree; - while (dek) { - dek=dek-8; - radix=(crc>>dek)&0xFF; - if (curusedtree->radix[radix]) { - curusedtree=curusedtree->radix[radix]; - } else { - /* radix not found, used is not in index */ - return 0; - } - } - for (i=0;inused;i++) { - if (strcmp(curusedtree->used[i],used)==0) { - return 1; - } - } - return 0; -} - - - -void InsertTextToTree(struct s_assenv *ae, char *text, char *replace, int crc) -{ - #undef FUNC - #define FUNC "InsertTextToTree" - - struct s_crcstring_tree *curstringtree; - int radix,dek=32,i; - - curstringtree=&ae->stringtree; - while (dek) { - dek=dek-8; - radix=(crc>>dek)&0xFF; - if (curstringtree->radix[radix]) { - curstringtree=curstringtree->radix[radix]; - } else { - curstringtree->radix[radix]=MemMalloc(sizeof(struct s_crcused_tree)); - curstringtree=curstringtree->radix[radix]; - memset(curstringtree,0,sizeof(struct s_crcused_tree)); - } - } - for (i=0;intext;i++) if (strcmp(text,curstringtree->text[i])==0) break; - /* no double */ - if (i==curstringtree->ntext) { - text=TxtStrDup(text); - replace=TxtStrDup(replace); - FieldArrayAddDynamicValueConcat(&curstringtree->text,&curstringtree->ntext,&curstringtree->mtext,text); - FieldArrayAddDynamicValueConcat(&curstringtree->replace,&curstringtree->nreplace,&curstringtree->mreplace,replace); - } -} - -void FreeTextTreeRecurse(struct s_crcstring_tree *lt) -{ - #undef FUNC - #define FUNC "FreeTextTreeRecurse" - - int i; - - for (i=0;i<256;i++) { - if (lt->radix[i]) { - FreeTextTreeRecurse(lt->radix[i]); - } - } - if (lt->mtext) { - for (i=0;intext;i++) MemFree(lt->text[i]); - MemFree(lt->text); - } - MemFree(lt); -} -void FreeTextTree(struct s_assenv *ae) -{ - #undef FUNC - #define FUNC "FreeTextTree" - - int i; - - for (i=0;i<256;i++) { - if (ae->stringtree.radix[i]) { - FreeTextTreeRecurse(ae->stringtree.radix[i]); - } - } - if (ae->stringtree.mtext) MemFree(ae->stringtree.text); -} -int SearchText(struct s_assenv *ae, char *text, int crc) -{ - #undef FUNC - #define FUNC "SearchText" - - struct s_crcstring_tree *curstringtree; - int i,radix,dek=32; - - curstringtree=&ae->stringtree; - while (dek) { - dek=dek-8; - radix=(crc>>dek)&0xFF; - if (curstringtree->radix[radix]) { - curstringtree=curstringtree->radix[radix]; - } else { - /* radix not found, used is not in index */ - return 0; - } - } - for (i=0;intext;i++) { - if (strcmp(curstringtree->text[i],text)==0) { - return 1; - } - } - return 0; -} - - - - - - - -/* -struct s_crclabel_tree { - - - - -/* -struct s_crclabel_tree { - struct s_crclabel_tree *radix[256]; - struct s_label *label; - int nlabel,mlabel; -}; -*/ -void FreeLabelTreeRecurse(struct s_crclabel_tree *lt) -{ - #undef FUNC - #define FUNC "FreeLabelTreeRecurse" - - int i; - - for (i=0;i<256;i++) { - if (lt->radix[i]) { - FreeLabelTreeRecurse(lt->radix[i]); - } - } - /* label.name already freed elsewhere as this one is a copy */ - if (lt->mlabel) MemFree(lt->label); - MemFree(lt); -} -void FreeLabelTree(struct s_assenv *ae) -{ - #undef FUNC - #define FUNC "FreeLabelTree" - - int i; - - for (i=0;i<256;i++) { - if (ae->labeltree.radix[i]) { - FreeLabelTreeRecurse(ae->labeltree.radix[i]); - } - } - if (ae->labeltree.mlabel) MemFree(ae->labeltree.label); -} - -struct s_label *SearchLabel(struct s_assenv *ae, char *label, int crc) -{ - #undef FUNC - #define FUNC "SearchLabel" - - struct s_crclabel_tree *curlabeltree; - struct s_label *retlabel=NULL; - int i,radix,dek=32; -//printf("searchLabel [%s]",label); - curlabeltree=&ae->labeltree; - while (dek) { - dek=dek-8; - radix=(crc>>dek)&0xFF; - if (curlabeltree->radix[radix]) { - curlabeltree=curlabeltree->radix[radix]; - } else { - /* radix not found, label is not in index */ -//printf(" not found\n"); - return NULL; - } - } - for (i=0;inlabel;i++) { - if (!curlabeltree->label[i].name && strcmp(ae->wl[curlabeltree->label[i].iw].w,label)==0) { - curlabeltree->label[i].used=1; -//printf(" found (global)\n"); - return &curlabeltree->label[i]; - } else if (curlabeltree->label[i].name && strcmp(curlabeltree->label[i].name,label)==0) { - curlabeltree->label[i].used=1; -//printf(" found (local or proximity)\n"); - return &curlabeltree->label[i]; - } - } - return NULL; -} - -char *MakeLocalLabel(struct s_assenv *ae,char *varbuffer, int *retdek) -{ - #undef FUNC - #define FUNC "MakeLocalLabel" - - char *locallabel; - char hexdigit[32]; - int lenbuf=0,dek,i,im; - char *zepoint; - - lenbuf=strlen(varbuffer); - - /* not so local labels */ - if (varbuffer[0]=='.') { - /* create reference */ - if (ae->lastgloballabel) { - locallabel=MemMalloc(strlen(varbuffer)+1+ae->lastgloballabellen); - sprintf(locallabel,"%s%s",ae->lastgloballabel,varbuffer); - if (retdek) *retdek=0; - return locallabel; - } else { - if (retdek) *retdek=0; - return TxtStrDup(varbuffer); - } - } - - /*************************************************** - without retdek -> build a local label - with retdek -> build the hash string - ***************************************************/ - if (!retdek) { - locallabel=MemMalloc(lenbuf+(ae->ir+ae->iw+3)*8+8); - zepoint=strchr(varbuffer,'.'); - if (zepoint) { - *zepoint=0; - } - strcpy(locallabel,varbuffer); - } else { - locallabel=MemMalloc((ae->ir+ae->iw+3)*8+4); - locallabel[0]=0; - } -//printf("locallabel=[%s] (draft)\n",locallabel); - - dek=0; - dek+=strappend(locallabel,"R"); - for (i=0;iir;i++) { - sprintf(hexdigit,"%04X",ae->repeat[i].cpt); - dek+=strappend(locallabel,hexdigit); - } - if (ae->ir) { - sprintf(hexdigit,"%04X",ae->repeat[ae->ir-1].value); - dek+=strappend(locallabel+dek,hexdigit); - } - - dek+=strappend(locallabel,"W"); - for (i=0;iiw;i++) { - sprintf(hexdigit,"%04X",ae->whilewend[i].cpt); - dek+=strappend(locallabel+dek,hexdigit); - } - if (ae->iw) { - sprintf(hexdigit,"%04X",ae->whilewend[ae->iw-1].value); - dek+=strappend(locallabel+dek,hexdigit); - } - /* where are we? */ - if (ae->imacropos) { - for (im=ae->imacropos-1;im>=0;im--) { - if (ae->idx>=ae->macropos[im].start && ae->idxmacropos[im].end) break; - } - if (im>=0) { - /* si on n'est pas dans une macro, on n'indique rien */ - sprintf(hexdigit,"M%04X",ae->macropos[im].value); - dek+=strappend(locallabel+dek,hexdigit); - } - } - if (!retdek) { - if (zepoint) { - *zepoint='.'; - strcat(locallabel+dek,zepoint); - } - } else { - *retdek=dek; - } -//printf("locallabel=[%s] (end)\n",locallabel); - return locallabel; -} - -char *TradExpression(char *zexp) -{ - #undef FUNC - #define FUNC "TradExpression" - - static char *last_expression=NULL; - char *wstr; - - if (last_expression) {MemFree(last_expression);last_expression=NULL;} - if (!zexp) return NULL; - - wstr=TxtStrDup(zexp); - wstr=TxtReplace(wstr,"[","<<",0); - wstr=TxtReplace(wstr,"]",">>",0); - wstr=TxtReplace(wstr,"m","%",0); - - last_expression=wstr; - return wstr; -} - -int TrimFloatingPointString(char *fps) { - int i=0,pflag,zflag=0; - - while (fps[i]) { - if (fps[i]=='.') { - pflag=i; - zflag=1; - } else if (fps[i]!='0') { - zflag=0; - } - i++; - } - /* truncate floating fract */ - if (zflag) { - fps[pflag]=0; - } else { - pflag=i; - } - return pflag; -} - - - -/* - translate tag or formula between curly brackets - used in label declaration - used in print directive -*/ -char *TranslateTag(struct s_assenv *ae, char *varbuffer, int *touched, int enablefast, int tagoption) { - /******************************************************* - v a r i a b l e s i n s t r i n g s - *******************************************************/ - char *starttag,*endtag,*tagcheck,*expr; - int newlen,lenw,taglen,tagidx,tagcount,validx; - char curvalstr[256]={0}; - char *equpos=NULL,*equback; - -//printf("TranslateTag [%s]\n",varbuffer); - - if (tagoption & E_TAGOPTION_PRESERVE) { - if (ae->iw || ae->ir) { - /* inside a loop we must care about variables */ -//printf("TranslateTag [%s] with PRESERVE inside a loop!\n",varbuffer); - return varbuffer; - } - } - - *touched=0; - while ((starttag=strchr(varbuffer+1,'{'))!=NULL) { - if ((endtag=strchr(starttag,'}'))==NULL) { - MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"invalid tag in string [%s]\n",varbuffer); - return NULL; - } - /* allow inception */ - tagcount=1; - tagcheck=starttag+1; - while (*tagcheck && tagcount) { - if (*tagcheck=='}') tagcount--; else if (*tagcheck=='{') tagcount++; - tagcheck++; - } - if (tagcount) { - MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"invalid brackets combination in string [%s]\n",varbuffer); - return NULL; - } else { - endtag=tagcheck-1; - } - *touched=1; - taglen=endtag-starttag+1; - tagidx=starttag-varbuffer; - lenw=strlen(varbuffer); // before the EOF write - *endtag=0; - /*** c o m p u t e e x p r e s s i o n ***/ - expr=TxtStrDup(starttag+1); - if (tagoption & E_TAGOPTION_REMOVESPACE) expr=TxtReplace(expr," ","",0); - if (enablefast) ExpressionFastTranslate(ae,&expr,0); - validx=(int)RoundComputeExpressionCore(ae,expr,ae->codeadr,0); - if (validx<0) { - strcpy(curvalstr,""); - MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"indexed tag must NOT be a negative value [%s]\n",varbuffer); - MemFree(expr); - return NULL; - } else { - #ifdef OS_WIN - snprintf(curvalstr,sizeof(curvalstr)-1,"%d",validx); - newlen=strlen(curvalstr); - #else - newlen=snprintf(curvalstr,sizeof(curvalstr)-1,"%d",validx); - #endif - } - MemFree(expr); - if (newlen>taglen) { - /* realloc */ - varbuffer=MemRealloc(varbuffer,lenw+newlen-taglen+1); - } - if (newlen!=taglen ) { - MemMove(varbuffer+tagidx+newlen,varbuffer+tagidx+taglen,lenw-taglen-tagidx+1); - } - strncpy(varbuffer+tagidx,curvalstr,newlen); /* copy without zero terminator */ - } - - return varbuffer; -} - -double ComputeExpressionCore(struct s_assenv *ae,char *original_zeexpression,int ptr, int didx) -{ - #undef FUNC - #define FUNC "ComputeExpressionCore" - - /* static execution buffers */ - static double *accu=NULL; - static int maccu=0; - static struct s_compute_element *computestack=NULL; - static int maxcomputestack=0; - int i,j,paccu=0; - int nbtokenstack=0; - int nbcomputestack=0; - int nboperatorstack=0; - - struct s_compute_element stackelement; - int o2,okclose,itoken; - - int idx=0,crc,icheck,is_binary,ivar=0; - char asciivalue[11]; - unsigned char c; - int accu_err=0; - /* backup alias replace */ - char *zeexpression,*expr; - int original=1; - int ialias,startvar; - int newlen,lenw; - /* dictionnary */ - struct s_expr_dico *curdic; - struct s_label *curlabel; - char *localname; - int minusptr,imkey,bank,page,idxmacro; - double curval; - /* negative value */ - int allow_minus_as_sign=0; - /* extended replace in labels */ - int curly=0,curlyflag=0; - char *Automate; - double dummint; - - /* memory cleanup */ - if (!ae) { - if (maccu) MemFree(accu); - accu=NULL;maccu=0; - if (maxcomputestack) MemFree(computestack); - computestack=NULL;maxcomputestack=0; -#if 0 - if (maxivar) MemFree(varbuffer); - if (maxtokenstack) MemFree(tokenstack); - if (maxoperatorstack) MemFree(operatorstack); - maxtokenstack=maxoperatorstack=0; - maxivar=1; - varbuffer=NULL; - tokenstack=NULL; - operatorstack=NULL; -#endif - return 0.0; - } - - /* be sure to have at least some bytes allocated */ - StateMachineResizeBuffer(&ae->computectx->varbuffer,128,&ae->computectx->maxivar); - - -#if TRACE_COMPUTE_EXPRESSION - printf("expression=[%s]\n",zeexpression); -#endif - zeexpression=original_zeexpression; - if (!zeexpression[0]) { - return 0; - } - /* double hack if the first value is negative */ - if (zeexpression[0]=='-') { - if (ae->AutomateExpressionValidCharFirst[(int)zeexpression[1]&0xFF]) { - allow_minus_as_sign=1; - } else { - memset(&stackelement,0,sizeof(stackelement)); - ObjectArrayAddDynamicValueConcat((void **)&ae->computectx->tokenstack,&nbtokenstack,&ae->computectx->maxtokenstack,&stackelement,sizeof(stackelement)); - } - } - - /* is there ascii char? */ - while ((c=zeexpression[idx])!=0) { - if (c=='\'' || c=='"') { - /* echappement */ - if (zeexpression[idx+1]=='\\') { - if (zeexpression[idx+2] && zeexpression[idx+3]==c) { - sprintf(asciivalue,"#%03X",zeexpression[idx+2]); - memcpy(zeexpression+idx,asciivalue,4); - idx+=3; - } else { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Only single escaped char may be quoted [%s]\n",TradExpression(zeexpression)); - zeexpression[0]=0; - return 0; - } - } else if (zeexpression[idx+1] && zeexpression[idx+2]==c) { - sprintf(asciivalue,"#%02X",zeexpression[idx+1]); - memcpy(zeexpression+idx,asciivalue,3); - idx+=2; - } else { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Only single char may be quoted [%s]\n",TradExpression(zeexpression)); - zeexpression[0]=0; - return 0; - } - } - - idx++; - } -#if TRACE_COMPUTE_EXPRESSION - printf("apres conversion des chars [%s]\n",zeexpression); -#endif - /*********************************************************** - P A T C H F O R P O S I T I V E V A L U E - ***********************************************************/ - if (zeexpression[0]=='+') idx=1; else idx=0; - /*********************************************************** - C O M P U T E E X P R E S S I O N M A I N L O O P - ***********************************************************/ - while ((c=zeexpression[idx])!=0) { - switch (c) { - /* parenthesis */ - case ')': - /* next to a closing parenthesis, a minus is an operator */ - allow_minus_as_sign=0; - break; - case '(': - /* operator detection */ - case '*': - case '/': - case '^': - case '[': - case 'm': - case '+': - case ']': - allow_minus_as_sign=1; - break; - case '&': - allow_minus_as_sign=1; - if (c=='&' && zeexpression[idx+1]=='&') { - idx++; - c='a'; // boolean AND - } - break; - case '|': - allow_minus_as_sign=1; - if (c=='|' && zeexpression[idx+1]=='|') { - idx++; - c='o'; // boolean OR - } - break; - /* testing */ - case '<': - allow_minus_as_sign=1; - if (zeexpression[idx+1]=='=') { - idx++; - c='k'; // boolean LOWEREQ - } else if (zeexpression[idx+1]=='>') { - idx++; - c='n'; // boolean NOTEQUAL - } else { - c='l'; - } - break; - case '>': - allow_minus_as_sign=1; - if (zeexpression[idx+1]=='=') { - idx++; - c='h'; // boolean GREATEREQ - } else { - c='g'; - } - break; - case '!': - allow_minus_as_sign=1; - if (zeexpression[idx+1]=='=') { - idx++; - c='n'; // boolean NOTEQUAL - } else { - c='b'; - } - break; - case '=': - allow_minus_as_sign=1; - /* expecting == */ - if (zeexpression[idx+1]=='=') { - idx++; - c='e'; // boolean EQUAL - /* except in maxam mode with a single = */ - } else if (ae->maxam) { - c='e'; // boolean EQUAL - /* cannot affect data inside an expression */ - } else { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] cannot set variable inside an expression\n",TradExpression(zeexpression)); - return 0; - } - break; - case '-': - if (allow_minus_as_sign) { - /* previous char was an opening parenthesis or an operator */ - ivar=0; - ae->computectx->varbuffer[ivar++]='-'; - StateMachineResizeBuffer(&ae->computectx->varbuffer,ivar,&ae->computectx->maxivar); - c=zeexpression[++idx]; - if (ae->AutomateExpressionValidCharFirst[(int)c&0xFF]) { - ae->computectx->varbuffer[ivar++]=c; - StateMachineResizeBuffer(&ae->computectx->varbuffer,ivar,&ae->computectx->maxivar); - c=zeexpression[++idx]; - while (ae->AutomateExpressionValidChar[(int)c&0xFF]) { - ae->computectx->varbuffer[ivar++]=c; - StateMachineResizeBuffer(&ae->computectx->varbuffer,ivar,&ae->computectx->maxivar); - c=zeexpression[++idx]; - } - } - ae->computectx->varbuffer[ivar]=0; - if (ivar<2) { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] invalid minus sign\n",TradExpression(zeexpression)); - if (!original) { - MemFree(zeexpression); - } - return 0; - } - break; - } - allow_minus_as_sign=1; - break; - - /* operator OR binary value */ - case '%': - /* % symbol may be a modulo or a binary literal value */ - is_binary=0; - for (icheck=1;zeexpression[idx+icheck];icheck++) { - switch (zeexpression[idx+icheck]) { - case '1': - case '0':/* still binary */ - is_binary=1; - break; - case '+': - case '-': - case '/': - case '*': - case '|': - case 'm': - case '%': - case '^': - case '&': - case '(': - case ')': - case '=': - case '<': - case '>': - case '!': - case '[': - case ']': - if (is_binary) is_binary=2; else is_binary=-1; - break; - default: - is_binary=-1; - } - if (is_binary==2) { - break; - } - if (is_binary==-1) { - is_binary=0; - break; - } - } - if (!is_binary) { - allow_minus_as_sign=1; - c='m'; - break; - } - default: - allow_minus_as_sign=0; - /* semantic analysis */ - startvar=idx; - ivar=0; - /* first char does not allow same chars as next chars */ - if (ae->AutomateExpressionValidCharFirst[((int)c)&0xFF]) { - ae->computectx->varbuffer[ivar++]=c; - if (c=='{') { - /* not a formula but only a prefix tag */ - curly++; - } - StateMachineResizeBuffer(&ae->computectx->varbuffer,ivar,&ae->computectx->maxivar); - idx++; - c=zeexpression[idx]; - Automate=ae->AutomateExpressionValidChar; - while (Automate[((int)c)&0xFF]) { - if (c=='{') { - curly++; - curlyflag=1; - Automate=ae->AutomateExpressionValidCharExtended; - } else if (c=='}') { - curly--; - if (!curly) { - Automate=ae->AutomateExpressionValidChar; - } - } - ae->computectx->varbuffer[ivar++]=c; - StateMachineResizeBuffer(&ae->computectx->varbuffer,ivar,&ae->computectx->maxivar); - idx++; - c=zeexpression[idx]; - } - } - ae->computectx->varbuffer[ivar]=0; - if (!ivar) { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"invalid char (%d=%c) expression [%s]\n",c,c>31?c:' ',TradExpression(zeexpression)); - if (!original) { - MemFree(zeexpression); - } - return 0; - } else if (curly) { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"wrong curly brackets in expression [%s]\n",TradExpression(zeexpression)); - if (!original) { - MemFree(zeexpression); - } - return 0; - } - } - if (c && !ivar) idx++; - - /************************************ - S T A C K D I S P A T C H E R - ************************************/ - /* push operator or stack value */ - if (!ivar) { - /************************************ - O P E R A T O R - ************************************/ - stackelement=ae->AutomateElement[c]; - if (stackelement.operator>E_COMPUTE_OPERATION_GREATEREQ) { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] has unknown operator %c (%d)\n",TradExpression(zeexpression),c>31?c:'.',c); - } - /* stackelement.value isn't used */ - } else { - /************************************ - V A L U E - ************************************/ -#if TRACE_COMPUTE_EXPRESSION - printf("value [%s]\n",ae->computectx->varbuffer); -#endif - if (ae->computectx->varbuffer[0]=='-') minusptr=1; else minusptr=0; - /* constantes ou variables/labels */ - switch (ae->computectx->varbuffer[minusptr]) { - case '0': - /* 0x hexa value hack */ - if (ae->computectx->varbuffer[minusptr+1]=='X' && ae->AutomateHexa[ae->computectx->varbuffer[minusptr+2]]) { - for (icheck=minusptr+3;ae->computectx->varbuffer[icheck];icheck++) { - if (ae->AutomateHexa[ae->computectx->varbuffer[icheck]]) continue; - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid hex number\n",TradExpression(zeexpression),ae->computectx->varbuffer); - break; - } - curval=strtol(ae->computectx->varbuffer+minusptr+2,NULL,16); - break; - } else - /* 0b binary value hack */ - if (ae->computectx->varbuffer[minusptr+1]=='B' && (ae->computectx->varbuffer[minusptr+2]>='0' && ae->computectx->varbuffer[minusptr+2]<='1')) { - for (icheck=minusptr+3;ae->computectx->varbuffer[icheck];icheck++) { - if (ae->computectx->varbuffer[icheck]>='0' && ae->computectx->varbuffer[icheck]<='1') continue; - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid binary number\n",TradExpression(zeexpression),ae->computectx->varbuffer); - break; - } - curval=strtol(ae->computectx->varbuffer+minusptr+2,NULL,2); - break; - } - /* 0o octal value hack */ - if (ae->computectx->varbuffer[minusptr+1]=='O' && (ae->computectx->varbuffer[minusptr+2]>='0' && ae->computectx->varbuffer[minusptr+2]<='5')) { - for (icheck=minusptr+3;ae->computectx->varbuffer[icheck];icheck++) { - if (ae->computectx->varbuffer[icheck]>='0' && ae->computectx->varbuffer[icheck]<='5') continue; - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid octal number\n",TradExpression(zeexpression),ae->computectx->varbuffer); - break; - } - curval=strtol(ae->computectx->varbuffer+minusptr+2,NULL,2); - break; - } - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - /* check number */ - for (icheck=minusptr;ae->computectx->varbuffer[icheck];icheck++) { - if (ae->AutomateDigit[ae->computectx->varbuffer[icheck]]) continue; - /* Intel hexa & binary style */ - switch (ae->computectx->varbuffer[strlen(ae->computectx->varbuffer)-1]) { - case 'H': - for (icheck=minusptr;ae->computectx->varbuffer[icheck+1];icheck++) { - if (ae->AutomateHexa[ae->computectx->varbuffer[icheck]]) continue; - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid hex number\n",TradExpression(zeexpression),ae->computectx->varbuffer); - } - curval=strtol(ae->computectx->varbuffer+minusptr,NULL,16); - break; - case 'B': - for (icheck=minusptr;ae->computectx->varbuffer[icheck+1];icheck++) { - if (ae->computectx->varbuffer[icheck]=='0' || ae->computectx->varbuffer[icheck]=='1') continue; - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid binary number\n",TradExpression(zeexpression),ae->computectx->varbuffer); - } - curval=strtol(ae->computectx->varbuffer+minusptr,NULL,2); - break; - default: - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid number\n",TradExpression(zeexpression),ae->computectx->varbuffer); - } - icheck=0; - break; - } - if (!ae->computectx->varbuffer[icheck]) curval=atof(ae->computectx->varbuffer+minusptr); - break; - case '%': - /* check number */ - if (!ae->computectx->varbuffer[minusptr+1]) { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is an empty binary number\n",TradExpression(zeexpression),ae->computectx->varbuffer); - } - for (icheck=minusptr+1;ae->computectx->varbuffer[icheck];icheck++) { - if (ae->computectx->varbuffer[icheck]=='0' || ae->computectx->varbuffer[icheck]=='1') continue; - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid binary number\n",TradExpression(zeexpression),ae->computectx->varbuffer); - break; - } - curval=strtol(ae->computectx->varbuffer+minusptr+1,NULL,2); - break; - case '#': - /* check number */ - if (!ae->computectx->varbuffer[minusptr+1]) { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is an empty hex number\n",TradExpression(zeexpression),ae->computectx->varbuffer); - } - for (icheck=minusptr+1;ae->computectx->varbuffer[icheck];icheck++) { - if (ae->AutomateHexa[ae->computectx->varbuffer[icheck]]) continue; - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid hex number\n",TradExpression(zeexpression),ae->computectx->varbuffer); - break; - } - curval=strtol(ae->computectx->varbuffer+minusptr+1,NULL,16); - break; - default: - if (1 || !curlyflag) { - /* $ hex value hack */ - if (ae->computectx->varbuffer[minusptr+0]=='$' && ae->AutomateHexa[ae->computectx->varbuffer[minusptr+1]]) { - for (icheck=minusptr+2;ae->computectx->varbuffer[icheck];icheck++) { - if (ae->AutomateHexa[ae->computectx->varbuffer[icheck]]) continue; - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid hex number\n",TradExpression(zeexpression),ae->computectx->varbuffer); - break; - } - curval=strtol(ae->computectx->varbuffer+minusptr+1,NULL,16); - break; - } - /* @ octal value hack */ - if (ae->computectx->varbuffer[minusptr+0]=='@' && ((ae->computectx->varbuffer[minusptr+1]>='0' && ae->computectx->varbuffer[minusptr+1]<='7'))) { - for (icheck=minusptr+2;ae->computectx->varbuffer[icheck];icheck++) { - if (ae->computectx->varbuffer[icheck]>='0' && ae->computectx->varbuffer[icheck]<='7') continue; - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid octal number\n",TradExpression(zeexpression),ae->computectx->varbuffer); - break; - } - curval=strtol(ae->computectx->varbuffer+minusptr+1,NULL,8); - break; - } - /* Intel hexa value hack */ - if (ae->AutomateHexa[ae->computectx->varbuffer[minusptr+0]]) { - if (ae->computectx->varbuffer[strlen(ae->computectx->varbuffer)-1]=='H') { - for (icheck=minusptr;ae->computectx->varbuffer[icheck+1];icheck++) { - if (!ae->AutomateHexa[ae->computectx->varbuffer[icheck]]) break; - } - if (!ae->computectx->varbuffer[icheck+1]) { - curval=strtol(ae->computectx->varbuffer+minusptr,NULL,16); - break; - } - } - } - } - - - if (curlyflag) { - char *minivarbuffer; - int touched; - - /* besoin d'un sous-contexte */ - minivarbuffer=TxtStrDup(ae->computectx->varbuffer+minusptr); - ae->computectx=&ae->ctx2; -#if TRACE_COMPUTE_EXPRESSION - printf("curly [%s]\n",minivarbuffer); -#endif - minivarbuffer=TranslateTag(ae,minivarbuffer, &touched,0,E_TAGOPTION_NONE); -#if TRACE_COMPUTE_EXPRESSION - printf("après curly [%s]\n",minivarbuffer); -#endif - ae->computectx=&ae->ctx1; - if (!touched) { - strcpy(ae->computectx->varbuffer+minusptr,minivarbuffer); - } else { - StateMachineResizeBuffer(&ae->computectx->varbuffer,strlen(minivarbuffer)+2,&ae->computectx->maxivar); - strcpy(ae->computectx->varbuffer+minusptr,minivarbuffer); - } - MemFree(minivarbuffer); - curlyflag=0; - } - - crc=GetCRC(ae->computectx->varbuffer+minusptr); - /*************************************************** - L O O K I N G F O R A F U N C T I O N - ***************************************************/ - for (imkey=0;math_keyword[imkey].mnemo[0];imkey++) { - if (crc==math_keyword[imkey].crc && strcmp(ae->computectx->varbuffer+minusptr,math_keyword[imkey].mnemo)==0) { - if (c=='(') { - /* push function as operator! */ - stackelement.operator=math_keyword[imkey].operation; - //stackelement.priority=0; - /************************************************ - C R E A T E E X T R A T O K E N - ************************************************/ - ObjectArrayAddDynamicValueConcat((void **)&ae->computectx->tokenstack,&nbtokenstack,&ae->computectx->maxtokenstack,&stackelement,sizeof(stackelement)); - stackelement.operator=E_COMPUTE_OPERATION_OPEN; - ObjectArrayAddDynamicValueConcat((void **)&ae->computectx->tokenstack,&nbtokenstack,&ae->computectx->maxtokenstack,&stackelement,sizeof(stackelement)); - allow_minus_as_sign=1; - idx++; - } else { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is a reserved keyword!\n",TradExpression(zeexpression),math_keyword[imkey].mnemo); - curval=0; - idx++; - } - ivar=0; - break; - } - } - if (math_keyword[imkey].mnemo[0]) continue; - - if (ae->computectx->varbuffer[minusptr+0]=='$' && ae->computectx->varbuffer[minusptr+1]==0) { - curval=ptr; - } else { -#if TRACE_COMPUTE_EXPRESSION - printf("search dico [%s]\n",ae->computectx->varbuffer+minusptr); -#endif - curdic=SearchDico(ae,ae->computectx->varbuffer+minusptr,crc); - if (curdic) { -#if TRACE_COMPUTE_EXPRESSION - printf("trouvé valeur=%.2lf\n",curdic->v); -#endif - curval=curdic->v; - break; - } else { - /* getbank hack */ - if (ae->computectx->varbuffer[minusptr]!='{') { - bank=0; - page=0; - } else if (strncmp(ae->computectx->varbuffer+minusptr,"{BANK}",6)==0) { - bank=6; - page=0; - /* obligé de recalculer le CRC */ - crc=GetCRC(ae->computectx->varbuffer+minusptr+bank); - } else if (strncmp(ae->computectx->varbuffer+minusptr,"{PAGE}",6)==0) { - bank=6; - page=1; - /* obligé de recalculer le CRC */ - crc=GetCRC(ae->computectx->varbuffer+minusptr+bank); - } else if (strncmp(ae->computectx->varbuffer+minusptr,"{PAGESET}",9)==0) { - bank=9; - page=2; - /* obligé de recalculer le CRC */ - crc=GetCRC(ae->computectx->varbuffer+minusptr+bank); - } else if (strncmp(ae->computectx->varbuffer+minusptr,"{SIZEOF}",8)==0) { - bank=8; - page=3; - /* obligé de recalculer le CRC */ - crc=GetCRC(ae->computectx->varbuffer+minusptr+bank); - /* search in structures prototypes and subfields */ - for (i=0;iirasmstruct;i++) { - if (ae->rasmstruct[i].crc==crc && strcmp(ae->rasmstruct[i].name,ae->computectx->varbuffer+minusptr+bank)==0) { - curval=ae->rasmstruct[i].size; - break; - } - - for (j=0;jrasmstruct[i].irasmstructfield;j++) { - if (ae->rasmstruct[i].rasmstructfield[j].crc==crc && strcmp(ae->rasmstruct[i].rasmstructfield[j].fullname,ae->computectx->varbuffer+minusptr+bank)==0) { - curval=ae->rasmstruct[i].rasmstructfield[j].size; - i=ae->irasmstruct+1; - break; - } - } - } - - if (i==ae->irasmstruct) { - /* search in structures aliases */ - for (i=0;iirasmstructalias;i++) { - if (ae->rasmstructalias[i].crc==crc && strcmp(ae->rasmstructalias[i].name,ae->computectx->varbuffer+minusptr+bank)==0) { - curval=ae->rasmstructalias[i].size+ae->rasmstructalias[i].ptr; - break; - } - } - if (i==ae->irasmstructalias) { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"cannot SIZEOF unknown structure [%s]!\n",ae->computectx->varbuffer+minusptr+bank); - curval=0; - } - } - } else { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is an unknown prefix!\n",TradExpression(zeexpression),ae->computectx->varbuffer); - } - /* limited label translation while processing crunched blocks - ae->curlz == current crunched block processed - expression->crunch_block=0 -> oui - expression->crunch_block=1 -> oui si même block - expression->crunch_block=2 -> non car sera relogée - */ - if (page!=3) { - -#if TRACE_COMPUTE_EXPRESSION -printf("search label [%s]\n",ae->computectx->varbuffer+minusptr+bank); -#endif - curlabel=SearchLabel(ae,ae->computectx->varbuffer+minusptr+bank,crc); - if (curlabel) { - if (ae->stage<2) { - if (curlabel->lz==-1) { - if (!bank) { - curval=curlabel->ptr; - } else { -#if TRACE_COMPUTE_EXPRESSION -printf("page=%d | ptr=%X ibank=%d\n",page,curlabel->ptr,curlabel->ibank); -#endif - switch (page) { - case 2: /* PAGESET */ - if (curlabel->ibanksetgate[curlabel->ibank]; - } else { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] cannot use PAGESET - label [%s] is in a temporary space!\n",TradExpression(zeexpression),ae->computectx->varbuffer); - curval=curlabel->ibank; - } - break; - case 1:/* PAGE */ - if (curlabel->ibankbankset[curlabel->ibank>>2]) { - curval=ae->bankgate[(curlabel->ibank&0x1FC)+(curlabel->ptr>>14)]; - } else { - curval=ae->bankgate[curlabel->ibank]; - } - } else { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] cannot use PAGE - label [%s] is in a temporary space!\n",TradExpression(zeexpression),ae->computectx->varbuffer); - curval=curlabel->ibank; - } - break; - case 0: - curval=curlabel->ibank; - break; - default:MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INTERNAL ERROR (unknown paging)\n",GetExpFile(ae,didx),GetExpLine(ae,didx));FreeAssenv(ae);exit(-664); - } - } - } else { - /* label MUST be in the crunched block */ - if (curlabel->iorgzone==ae->expression[didx].iorgzone && curlabel->ibank==ae->expression[didx].ibank && curlabel->lz<=ae->expression[didx].lz) { - if (!bank) { - curval=curlabel->ptr; - } else { - if (page) { - switch (page) { - case 2: /* PAGESET */ - if (curlabel->ibanksetgate[curlabel->ibank]; - } else { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] cannot use PAGESET - label [%s] is in a temporary space!\n",TradExpression(zeexpression),ae->computectx->varbuffer); - curval=curlabel->ibank; - } - break; - case 1: /* PAGE */ - if (curlabel->ibankbankset[curlabel->ibank>>2]) { - curval=ae->bankgate[(curlabel->ibank&0x1FC)+(curlabel->ptr>>14)]; - } else { - curval=ae->bankgate[curlabel->ibank]; - } - } else { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] cannot use PAGE - label [%s] is in a temporary space!\n",TradExpression(zeexpression),ae->computectx->varbuffer); - curval=curlabel->ibank; - } - break; - case 0:curval=curlabel->ibank;break; - default:MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INTERNAL ERROR (unknown paging)\n",GetExpFile(ae,didx),GetExpLine(ae,didx));FreeAssenv(ae);exit(-664); - } - } - } - } else { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Label [%s](%d) cannot be computed because it is located after the crunched zone %d\n",ae->computectx->varbuffer,curlabel->lz,ae->expression[didx].lz); - curval=0; - } - } - } else { -#if TRACE_COMPUTE_EXPRESSION -printf("stage 2 | page=%d | ptr=%X ibank=%d\n",page,curlabel->ptr,curlabel->ibank); -#endif - if (bank) { - //curval=curlabel->ibank; - switch (page) { - case 2: /* PAGESET */ - if (curlabel->ibanksetgate[curlabel->ibank]; - } else { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] cannot use PAGESET - label [%s] is in a temporary space!\n",TradExpression(zeexpression),ae->computectx->varbuffer); - curval=curlabel->ibank; - } - break; - case 1:/* PAGE */ - if (curlabel->ibankbankset[curlabel->ibank>>2]) { - curval=ae->bankgate[(curlabel->ibank&0x1FC)+(curlabel->ptr>>14)]; - } else { - curval=ae->bankgate[curlabel->ibank]; - } - } else { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] cannot use PAGE - label [%s] is in a temporary space!\n",TradExpression(zeexpression),ae->computectx->varbuffer); - curval=curlabel->ibank; - } - break; - case 0: - curval=curlabel->ibank; - break; - default:MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INTERNAL ERROR (unknown paging)\n",GetExpFile(ae,didx),GetExpLine(ae,didx));FreeAssenv(ae);exit(-664); - } - } else { - curval=curlabel->ptr; - } - } - } else { - /*********** - to allow aliases declared after use - ***********/ - if ((ialias=SearchAlias(ae,crc,ae->computectx->varbuffer+minusptr))>=0) { - newlen=ae->alias[ialias].len; - lenw=strlen(zeexpression); - if (newlen>ivar) { - /* realloc bigger */ - if (original) { - expr=MemMalloc(lenw+newlen-ivar+1); - memcpy(expr,zeexpression,lenw+1); - zeexpression=expr; - original=0; - } else { - zeexpression=MemRealloc(zeexpression,lenw+newlen-ivar+1); - } - } - /* startvar? */ - if (newlen!=ivar) { - MemMove(zeexpression+startvar+newlen,zeexpression+startvar+ivar,lenw-startvar-ivar+1); - } - strncpy(zeexpression+startvar,ae->alias[ialias].translation,newlen); /* copy without zero terminator */ - idx=startvar; - ivar=0; - continue; - } else { - /* index possible sur une struct? */ - int reverse_idx,validx=-1; - char *structlabel; - - reverse_idx=strlen(ae->computectx->varbuffer)-1; - if (ae->computectx->varbuffer[reverse_idx]>='0' && ae->computectx->varbuffer[reverse_idx]<='9') { - /* vu que ça ne PEUT PAS être une valeur litérale, on ne fait pas de test de débordement */ - reverse_idx--; - while (ae->computectx->varbuffer[reverse_idx]>='0' && ae->computectx->varbuffer[reverse_idx]<='9') { - reverse_idx--; - } - reverse_idx++; - validx=atoi(ae->computectx->varbuffer+reverse_idx); - structlabel=TxtStrDup(ae->computectx->varbuffer+minusptr); - structlabel[reverse_idx-minusptr]=0; -#ifdef TRACE_STRUCT - printf("EVOL 119 -> looking for struct %s IDX=%d\n",structlabel,validx); -#endif - /* unoptimized search in structures aliases */ - crc=GetCRC(structlabel); - for (i=0;iirasmstructalias;i++) { - if (ae->rasmstructalias[i].crc==crc && strcmp(ae->rasmstructalias[i].name,structlabel)==0) { -#ifdef TRACE_STRUCT - printf("EVOL 119 -> found! ptr=%d size=%d\n",ae->rasmstructalias[i].ptr,ae->rasmstructalias[i].size); -#endif - curval=ae->rasmstructalias[i].size*validx+ae->rasmstructalias[i].ptr; - if (validx>=ae->rasmstructalias[i].nbelem) { - if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: index out of array size!\n",GetExpFile(ae,didx),GetExpLine(ae,didx)); - } - break; - } - } - if (i==ae->irasmstructalias) { - /* not found */ - validx=-1; - } - MemFree(structlabel); - } - if (validx<0) { - /* last chance to get a keyword */ - if (strcmp(ae->computectx->varbuffer+minusptr,"REPEAT_COUNTER")==0) { - if (ae->ir) { - curval=ae->repeat[ae->ir-1].repeat_counter; - } else { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"cannot use REPEAT_COUNTER keyword outside a repeat loop\n"); - curval=0; - } - } else if (strcmp(ae->computectx->varbuffer+minusptr,"WHILE_COUNTER")==0) { - if (ae->iw) { - curval=ae->whilewend[ae->iw-1].while_counter; - } else { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"cannot use WHILE_COUNTER keyword outside a while loop\n"); - curval=0; - } - } else { - /* in case the expression is a register */ - if (IsRegister(ae->computectx->varbuffer+minusptr)) { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"cannot use register %s in this context\n",TradExpression(zeexpression)); - } else { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] keyword [%s] not found in variables, labels or aliases\n",TradExpression(zeexpression),ae->computectx->varbuffer+minusptr); - if (ae->extended_error) { - char *lookstr; - lookstr=StringLooksLike(ae,ae->computectx->varbuffer+minusptr); - if (lookstr) { - rasm_printf(ae,KERROR" did you mean [%s] ?\n",lookstr); - } - } - } - - curval=0; - } - } - } - } - } - } - } - } - if (minusptr) curval=-curval; - stackelement.operator=E_COMPUTE_OPERATION_PUSH_DATASTC; - stackelement.value=curval; - /* priority isn't used */ - - allow_minus_as_sign=0; - ivar=0; - } - /************************************ - C R E A T E T O K E N - ************************************/ - ObjectArrayAddDynamicValueConcat((void **)&ae->computectx->tokenstack,&nbtokenstack,&ae->computectx->maxtokenstack,&stackelement,sizeof(stackelement)); - } - /******************************************************* - C R E A T E E X E C U T I O N S T A C K - *******************************************************/ -#define DEBUG_STACK 0 -#if DEBUG_STACK - for (itoken=0;itokencomputectx->tokenstack[itoken].operator) { - case E_COMPUTE_OPERATION_PUSH_DATASTC:printf("%lf ",ae->computectx->tokenstack[itoken].value);break; - case E_COMPUTE_OPERATION_OPEN:printf("(");break; - case E_COMPUTE_OPERATION_CLOSE:printf(")");break; - case E_COMPUTE_OPERATION_ADD:printf("+ ");break; - case E_COMPUTE_OPERATION_SUB:printf("- ");break; - case E_COMPUTE_OPERATION_DIV:printf("/ ");break; - case E_COMPUTE_OPERATION_MUL:printf("* ");break; - case E_COMPUTE_OPERATION_AND:printf("and ");break; - case E_COMPUTE_OPERATION_OR:printf("or ");break; - case E_COMPUTE_OPERATION_MOD:printf("mod ");break; - case E_COMPUTE_OPERATION_XOR:printf("xor ");break; - case E_COMPUTE_OPERATION_NOT:printf("! ");break; - case E_COMPUTE_OPERATION_SHL:printf("<< ");break; - case E_COMPUTE_OPERATION_SHR:printf(">> ");break; - case E_COMPUTE_OPERATION_BAND:printf("&& ");break; - case E_COMPUTE_OPERATION_BOR:printf("|| ");break; - case E_COMPUTE_OPERATION_LOWER:printf("< ");break; - case E_COMPUTE_OPERATION_GREATER:printf("> ");break; - case E_COMPUTE_OPERATION_EQUAL:printf("== ");break; - case E_COMPUTE_OPERATION_NOTEQUAL:printf("!= ");break; - case E_COMPUTE_OPERATION_LOWEREQ:printf("<= ");break; - case E_COMPUTE_OPERATION_GREATEREQ:printf(">= ");break; - case E_COMPUTE_OPERATION_SIN:printf("sin ");break; - case E_COMPUTE_OPERATION_COS:printf("cos ");break; - case E_COMPUTE_OPERATION_INT:printf("int ");break; - case E_COMPUTE_OPERATION_FLOOR:printf("floor ");break; - case E_COMPUTE_OPERATION_ABS:printf("abs ");break; - case E_COMPUTE_OPERATION_LN:printf("ln ");break; - case E_COMPUTE_OPERATION_LOG10:printf("log10 ");break; - case E_COMPUTE_OPERATION_SQRT:printf("sqrt ");break; - case E_COMPUTE_OPERATION_ASIN:printf("asin ");break; - case E_COMPUTE_OPERATION_ACOS:printf("acos ");break; - case E_COMPUTE_OPERATION_ATAN:printf("atan ");break; - case E_COMPUTE_OPERATION_EXP:printf("exp ");break; - case E_COMPUTE_OPERATION_LOW:printf("low ");break; - case E_COMPUTE_OPERATION_HIGH:printf("high ");break; - case E_COMPUTE_OPERATION_PSG:printf("psg ");break; - case E_COMPUTE_OPERATION_RND:printf("rnd ");break; - case E_COMPUTE_OPERATION_FRAC:printf("frac ");break; - case E_COMPUTE_OPERATION_CEIL:printf("ceil ");break; - case E_COMPUTE_OPERATION_GET_R:printf("get_r ");break; - case E_COMPUTE_OPERATION_GET_V:printf("get_v ");break; - case E_COMPUTE_OPERATION_GET_B:printf("get_b ");break; - case E_COMPUTE_OPERATION_SET_R:printf("set_r ");break; - case E_COMPUTE_OPERATION_SET_V:printf("set_v ");break; - case E_COMPUTE_OPERATION_SET_B:printf("set_b ");break; - default:printf("bug\n");break; - } - - } - printf("\n"); -#endif - - for (itoken=0;itokencomputectx->tokenstack[itoken].operator) { - case E_COMPUTE_OPERATION_PUSH_DATASTC: -#if DEBUG_STACK -printf("data\n"); -#endif - ObjectArrayAddDynamicValueConcat((void **)&computestack,&nbcomputestack,&maxcomputestack,&ae->computectx->tokenstack[itoken],sizeof(stackelement)); - break; - case E_COMPUTE_OPERATION_OPEN: - ObjectArrayAddDynamicValueConcat((void **)&ae->computectx->operatorstack,&nboperatorstack,&ae->computectx->maxoperatorstack,&ae->computectx->tokenstack[itoken],sizeof(stackelement)); -#if DEBUG_STACK -printf("ajout (\n"); -#endif - break; - case E_COMPUTE_OPERATION_CLOSE: -#if DEBUG_STACK -printf("close\n"); -#endif - /* pop out token until the opened parenthesis is reached */ - o2=nboperatorstack-1; - okclose=0; - while (o2>=0) { - if (ae->computectx->operatorstack[o2].operator!=E_COMPUTE_OPERATION_OPEN) { - ObjectArrayAddDynamicValueConcat((void **)&computestack,&nbcomputestack,&maxcomputestack,&ae->computectx->operatorstack[o2],sizeof(stackelement)); - nboperatorstack--; -#if DEBUG_STACK -printf("op--\n"); -#endif - o2--; - } else { - /* discard opening parenthesis as operator */ -#if DEBUG_STACK -printf("discard )\n"); -#endif - nboperatorstack--; - okclose=1; - o2--; - break; - } - } - if (!okclose) { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"missing parenthesis [%s]\n",TradExpression(zeexpression)); - if (!original) { - MemFree(zeexpression); - } - return 0; - } - /* if upper token is a function then pop from the stack */ - if (o2>=0 && ae->computectx->operatorstack[o2].operator>=E_COMPUTE_OPERATION_SIN) { - ObjectArrayAddDynamicValueConcat((void **)&computestack,&nbcomputestack,&maxcomputestack,&ae->computectx->operatorstack[o2],sizeof(stackelement)); - nboperatorstack--; -#if DEBUG_STACK -printf("pop function\n"); -#endif - } - break; - case E_COMPUTE_OPERATION_ADD: - case E_COMPUTE_OPERATION_SUB: - case E_COMPUTE_OPERATION_DIV: - case E_COMPUTE_OPERATION_MUL: - case E_COMPUTE_OPERATION_AND: - case E_COMPUTE_OPERATION_OR: - case E_COMPUTE_OPERATION_MOD: - case E_COMPUTE_OPERATION_XOR: - case E_COMPUTE_OPERATION_NOT: - case E_COMPUTE_OPERATION_SHL: - case E_COMPUTE_OPERATION_SHR: - case E_COMPUTE_OPERATION_BAND: - case E_COMPUTE_OPERATION_BOR: - case E_COMPUTE_OPERATION_LOWER: - case E_COMPUTE_OPERATION_GREATER: - case E_COMPUTE_OPERATION_EQUAL: - case E_COMPUTE_OPERATION_NOTEQUAL: - case E_COMPUTE_OPERATION_LOWEREQ: - case E_COMPUTE_OPERATION_GREATEREQ: -#if DEBUG_STACK -printf("operator\n"); -#endif - o2=nboperatorstack-1; - while (o2>=0 && ae->computectx->operatorstack[o2].operator!=E_COMPUTE_OPERATION_OPEN) { - if (ae->computectx->tokenstack[itoken].priority>=ae->computectx->operatorstack[o2].priority || ae->computectx->operatorstack[o2].operator>=E_COMPUTE_OPERATION_SIN) { - ObjectArrayAddDynamicValueConcat((void **)&computestack,&nbcomputestack,&maxcomputestack,&ae->computectx->operatorstack[o2],sizeof(stackelement)); - nboperatorstack--; - o2--; - } else { - break; - } - } - ObjectArrayAddDynamicValueConcat((void **)&ae->computectx->operatorstack,&nboperatorstack,&ae->computectx->maxoperatorstack,&ae->computectx->tokenstack[itoken],sizeof(stackelement)); - break; - case E_COMPUTE_OPERATION_SIN: - case E_COMPUTE_OPERATION_COS: - case E_COMPUTE_OPERATION_INT: - case E_COMPUTE_OPERATION_FLOOR: - case E_COMPUTE_OPERATION_ABS: - case E_COMPUTE_OPERATION_LN: - case E_COMPUTE_OPERATION_LOG10: - case E_COMPUTE_OPERATION_SQRT: - case E_COMPUTE_OPERATION_ASIN: - case E_COMPUTE_OPERATION_ACOS: - case E_COMPUTE_OPERATION_ATAN: - case E_COMPUTE_OPERATION_EXP: - case E_COMPUTE_OPERATION_LOW: - case E_COMPUTE_OPERATION_HIGH: - case E_COMPUTE_OPERATION_PSG: - case E_COMPUTE_OPERATION_RND: - case E_COMPUTE_OPERATION_FRAC: - case E_COMPUTE_OPERATION_CEIL: - case E_COMPUTE_OPERATION_GET_R: - case E_COMPUTE_OPERATION_GET_V: - case E_COMPUTE_OPERATION_GET_B: - case E_COMPUTE_OPERATION_SET_R: - case E_COMPUTE_OPERATION_SET_V: - case E_COMPUTE_OPERATION_SET_B: -#if DEBUG_STACK -printf("ajout de la fonction\n"); -#endif - ObjectArrayAddDynamicValueConcat((void **)&ae->computectx->operatorstack,&nboperatorstack,&ae->computectx->maxoperatorstack,&ae->computectx->tokenstack[itoken],sizeof(stackelement)); - break; - default:break; - } - } - /* pop remaining operators */ - while (nboperatorstack>0) { - ObjectArrayAddDynamicValueConcat((void **)&computestack,&nbcomputestack,&maxcomputestack,&ae->computectx->operatorstack[--nboperatorstack],sizeof(stackelement)); - } - - /******************************************** - E X E C U T E S T A C K - ********************************************/ - if (ae->maxam || ae->as80) { - int workinterval; - if (ae->as80) workinterval=0xFFFFFFFF; else workinterval=0xFFFF; - for (i=0;i1) accu[paccu-2]=((int)accu[paccu-2]+(int)accu[paccu-1])&workinterval;paccu--;break; - case E_COMPUTE_OPERATION_SUB:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]-(int)accu[paccu-1])&workinterval;paccu--;break; - case E_COMPUTE_OPERATION_MUL:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]*(int)accu[paccu-1])&workinterval;paccu--;break; - case E_COMPUTE_OPERATION_DIV:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]/(int)accu[paccu-1])&workinterval;paccu--;break; - case E_COMPUTE_OPERATION_AND:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]&(int)accu[paccu-1])&workinterval;paccu--;break; - case E_COMPUTE_OPERATION_OR:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]|(int)accu[paccu-1])&workinterval;paccu--;break; - case E_COMPUTE_OPERATION_XOR:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]^(int)accu[paccu-1])&workinterval;paccu--;break; - case E_COMPUTE_OPERATION_MOD:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]%(int)accu[paccu-1])&workinterval;paccu--;break; - case E_COMPUTE_OPERATION_SHL:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2])<<((int)accu[paccu-1]); - if (((int)accu[paccu-1])>31 || ((int)accu[paccu-1])<-31) { - if (!ae->nowarning) { - rasm_printf(ae,KWARNING"Warning - shifting %d is architecture dependant, result forced to ZERO\n",(int)accu[paccu-1]); - } - accu[paccu-2]=0; - } - paccu--;break; - case E_COMPUTE_OPERATION_SHR:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2])>>((int)accu[paccu-1]); - if (((int)accu[paccu-1])>31 || ((int)accu[paccu-1])<-31) { - if (!ae->nowarning) { - rasm_printf(ae,KWARNING"Warning - shifting %d is architecture dependant, result forced to ZERO\n",(int)accu[paccu-1]); - } - accu[paccu-2]=0; - } - paccu--;break; - case E_COMPUTE_OPERATION_BAND:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]&&(int)accu[paccu-1])&workinterval;paccu--;break; - case E_COMPUTE_OPERATION_BOR:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]||(int)accu[paccu-1])&workinterval;paccu--;break; - /* comparison */ - case E_COMPUTE_OPERATION_LOWER:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]&workinterval)<((int)accu[paccu-1]&workinterval);paccu--;break; - case E_COMPUTE_OPERATION_LOWEREQ:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]&workinterval)<=((int)accu[paccu-1]&workinterval);paccu--;break; - case E_COMPUTE_OPERATION_EQUAL:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]&workinterval)==((int)accu[paccu-1]&workinterval);paccu--;break; - case E_COMPUTE_OPERATION_NOTEQUAL:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]&workinterval)!=((int)accu[paccu-1]&workinterval);paccu--;break; - case E_COMPUTE_OPERATION_GREATER:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]&workinterval)>((int)accu[paccu-1]&workinterval);paccu--;break; - case E_COMPUTE_OPERATION_GREATEREQ:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]&workinterval)>=((int)accu[paccu-1]&workinterval);paccu--;break; - /* functions */ - case E_COMPUTE_OPERATION_SIN:if (paccu>0) accu[paccu-1]=(int)sin(accu[paccu-1]*3.1415926545/180.0);break; - case E_COMPUTE_OPERATION_COS:if (paccu>0) accu[paccu-1]=(int)cos(accu[paccu-1]*3.1415926545/180.0);break; - case E_COMPUTE_OPERATION_ASIN:if (paccu>0) accu[paccu-1]=(int)asin(accu[paccu-1])*180.0/3.1415926545;break; - case E_COMPUTE_OPERATION_ACOS:if (paccu>0) accu[paccu-1]=(int)acos(accu[paccu-1])*180.0/3.1415926545;break; - case E_COMPUTE_OPERATION_ATAN:if (paccu>0) accu[paccu-1]=(int)atan(accu[paccu-1])*180.0/3.1415926545;break; - case E_COMPUTE_OPERATION_INT:break; - case E_COMPUTE_OPERATION_FLOOR:if (paccu>0) accu[paccu-1]=(int)floor(accu[paccu-1])&workinterval;break; - case E_COMPUTE_OPERATION_ABS:if (paccu>0) accu[paccu-1]=(int)fabs(accu[paccu-1])&workinterval;break; - case E_COMPUTE_OPERATION_EXP:if (paccu>0) accu[paccu-1]=(int)exp(accu[paccu-1])&workinterval;break; - case E_COMPUTE_OPERATION_LN:if (paccu>0) accu[paccu-1]=(int)log(accu[paccu-1])&workinterval;break; - case E_COMPUTE_OPERATION_LOG10:if (paccu>0) accu[paccu-1]=(int)log10(accu[paccu-1])&workinterval;break; - case E_COMPUTE_OPERATION_SQRT:if (paccu>0) accu[paccu-1]=(int)sqrt(accu[paccu-1])&workinterval;break; - case E_COMPUTE_OPERATION_LOW:if (paccu>0) accu[paccu-1]=((int)accu[paccu-1])&0xFF;break; - case E_COMPUTE_OPERATION_HIGH:if (paccu>0) accu[paccu-1]=(((int)accu[paccu-1])&0xFF00)>>8;break; - case E_COMPUTE_OPERATION_PSG:if (paccu>0) accu[paccu-1]=ae->psgfine[((int)accu[paccu-1])&0xFF];break; - case E_COMPUTE_OPERATION_RND:if (paccu>0) accu[paccu-1]=rand()%((int)accu[paccu-1]);break; - case E_COMPUTE_OPERATION_FRAC:if (paccu>0) accu[paccu-1]=((int)(accu[paccu-1]-(int)accu[paccu-1]));break; - case E_COMPUTE_OPERATION_CEIL:if (paccu>0) accu[paccu-1]=(int)ceil(accu[paccu-1])&workinterval;break; - case E_COMPUTE_OPERATION_GET_R:if (paccu>0) accu[paccu-1]=((((int)accu[paccu-1])&0xF0)>>4);break; - case E_COMPUTE_OPERATION_GET_V:if (paccu>0) accu[paccu-1]=((((int)accu[paccu-1])&0xF00)>>8);break; - case E_COMPUTE_OPERATION_GET_B:if (paccu>0) accu[paccu-1]=(((int)accu[paccu-1])&0xF);break; - case E_COMPUTE_OPERATION_SET_R:if (paccu>0) accu[paccu-1]=MinMaxInt(accu[paccu-1],0,15)<<4;break; - case E_COMPUTE_OPERATION_SET_V:if (paccu>0) accu[paccu-1]=MinMaxInt(accu[paccu-1],0,15)<<8;break; - case E_COMPUTE_OPERATION_SET_B:if (paccu>0) accu[paccu-1]=MinMaxInt(accu[paccu-1],0,15);break; - default:MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"invalid computing state! (%d)\n",GetExpFile(ae,didx),GetExpLine(ae,didx),computestack[i].operator);paccu=0; - } - if (!paccu) { - if (zeexpression[0]=='&') { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Missing operand for calculation [%s] Did you use & for an hexadecimal value?\n",TradExpression(zeexpression)); - } else { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Missing operand for calculation [%s]\n",TradExpression(zeexpression)); - } - accu_err=1; - break; - } - } - } else { - for (i=0;i>": - computestack[i].operator==E_COMPUTE_OPERATION_LOWER?"<": - computestack[i].operator==E_COMPUTE_OPERATION_GREATER?">": - computestack[i].operator==E_COMPUTE_OPERATION_EQUAL?"==": - computestack[i].operator==E_COMPUTE_OPERATION_INT?"INT": - computestack[i].operator==E_COMPUTE_OPERATION_LOWEREQ?"<=": - computestack[i].operator==E_COMPUTE_OPERATION_GREATEREQ?">=": - computestack[i].operator==E_COMPUTE_OPERATION_OPEN?"(": - computestack[i].operator==E_COMPUTE_OPERATION_CLOSE?")": - "",computestack[i].priority); - } -#endif - switch (computestack[i].operator) { - case E_COMPUTE_OPERATION_PUSH_DATASTC: - if (maccu<=paccu) { - maccu=16+paccu; - accu=MemRealloc(accu,sizeof(double)*maccu); - } - accu[paccu]=computestack[i].value;paccu++; - break; - case E_COMPUTE_OPERATION_OPEN: - case E_COMPUTE_OPERATION_CLOSE: /* cannot happend */ break; - case E_COMPUTE_OPERATION_ADD:if (paccu>1) accu[paccu-2]+=accu[paccu-1];paccu--;break; - case E_COMPUTE_OPERATION_SUB:if (paccu>1) accu[paccu-2]-=accu[paccu-1];paccu--;break; - case E_COMPUTE_OPERATION_MUL:if (paccu>1) accu[paccu-2]*=accu[paccu-1];paccu--;break; - case E_COMPUTE_OPERATION_DIV:if (paccu>1) accu[paccu-2]/=accu[paccu-1];paccu--;break; - case E_COMPUTE_OPERATION_AND:if (paccu>1) accu[paccu-2]=((int)floor(accu[paccu-2]+0.5))&((int)floor(accu[paccu-1]+0.5));paccu--;break; - case E_COMPUTE_OPERATION_OR:if (paccu>1) accu[paccu-2]=((int)floor(accu[paccu-2]+0.5))|((int)floor(accu[paccu-1]+0.5));paccu--;break; - case E_COMPUTE_OPERATION_XOR:if (paccu>1) accu[paccu-2]=((int)floor(accu[paccu-2]+0.5))^((int)floor(accu[paccu-1]+0.5));paccu--;break; - case E_COMPUTE_OPERATION_NOT:/* half operator, half function */ if (paccu>0) accu[paccu-1]=!((int)floor(accu[paccu-1]+0.5));break; - case E_COMPUTE_OPERATION_MOD:if (paccu>1) accu[paccu-2]=((int)floor(accu[paccu-2]+0.5))%((int)floor(accu[paccu-1]+0.5));paccu--;break; - case E_COMPUTE_OPERATION_SHL:if (paccu>1) accu[paccu-2]=((int)floor(accu[paccu-2]+0.5))<<((int)floor(accu[paccu-1]+0.5)); - if (((int)accu[paccu-1])>31 || ((int)accu[paccu-1])<-31) { - if (!ae->nowarning) { - rasm_printf(ae,KWARNING"Warning - shifting %d is architecture dependant, result forced to ZERO\n",(int)accu[paccu-1]); - } - accu[paccu-2]=0; - } - paccu--;break; - case E_COMPUTE_OPERATION_SHR:if (paccu>1) accu[paccu-2]=((int)floor(accu[paccu-2]+0.5))>>((int)floor(accu[paccu-1]+0.5)); - if (((int)accu[paccu-1])>31 || ((int)accu[paccu-1])<-31) { - if (!ae->nowarning) { - rasm_printf(ae,KWARNING"Warning - shifting %d is architecture dependant, result forced to ZERO\n",(int)accu[paccu-1]); - } - accu[paccu-2]=0; - } - paccu--;break; - case E_COMPUTE_OPERATION_BAND:if (paccu>1) accu[paccu-2]=((int)floor(accu[paccu-2]+0.5))&&((int)floor(accu[paccu-1]+0.5));paccu--;break; - case E_COMPUTE_OPERATION_BOR:if (paccu>1) accu[paccu-2]=((int)floor(accu[paccu-2]+0.5))||((int)floor(accu[paccu-1]+0.5));paccu--;break; - /* comparison */ - case E_COMPUTE_OPERATION_LOWER:if (paccu>1) accu[paccu-2]=accu[paccu-2]1) accu[paccu-2]=accu[paccu-2]<=accu[paccu-1];paccu--;break; - case E_COMPUTE_OPERATION_EQUAL:if (paccu>1) accu[paccu-2]=fabs(accu[paccu-2]-accu[paccu-1])<0.000001;paccu--;break; - case E_COMPUTE_OPERATION_NOTEQUAL:if (paccu>1) accu[paccu-2]=accu[paccu-2]!=accu[paccu-1];paccu--;break; - case E_COMPUTE_OPERATION_GREATER:if (paccu>1) accu[paccu-2]=accu[paccu-2]>accu[paccu-1];paccu--;break; - case E_COMPUTE_OPERATION_GREATEREQ:if (paccu>1) accu[paccu-2]=accu[paccu-2]>=accu[paccu-1];paccu--;break; - /* functions */ - case E_COMPUTE_OPERATION_SIN:if (paccu>0) accu[paccu-1]=sin(accu[paccu-1]*3.1415926545/180.0);break; - case E_COMPUTE_OPERATION_COS:if (paccu>0) accu[paccu-1]=cos(accu[paccu-1]*3.1415926545/180.0);break; - case E_COMPUTE_OPERATION_ASIN:if (paccu>0) accu[paccu-1]=asin(accu[paccu-1])*180.0/3.1415926545;break; - case E_COMPUTE_OPERATION_ACOS:if (paccu>0) accu[paccu-1]=acos(accu[paccu-1])*180.0/3.1415926545;break; - case E_COMPUTE_OPERATION_ATAN:if (paccu>0) accu[paccu-1]=atan(accu[paccu-1])*180.0/3.1415926545;break; - case E_COMPUTE_OPERATION_INT:if (paccu>0) accu[paccu-1]=floor(accu[paccu-1]+0.5);break; - case E_COMPUTE_OPERATION_FLOOR:if (paccu>0) accu[paccu-1]=floor(accu[paccu-1]);break; - case E_COMPUTE_OPERATION_ABS:if (paccu>0) accu[paccu-1]=fabs(accu[paccu-1]);break; - case E_COMPUTE_OPERATION_EXP:if (paccu>0) accu[paccu-1]=exp(accu[paccu-1]);break; - case E_COMPUTE_OPERATION_LN:if (paccu>0) accu[paccu-1]=log(accu[paccu-1]);break; - case E_COMPUTE_OPERATION_LOG10:if (paccu>0) accu[paccu-1]=log10(accu[paccu-1]);break; - case E_COMPUTE_OPERATION_SQRT:if (paccu>0) accu[paccu-1]=sqrt(accu[paccu-1]);break; - case E_COMPUTE_OPERATION_LOW:if (paccu>0) accu[paccu-1]=((int)floor(accu[paccu-1]+0.5))&0xFF;break; - case E_COMPUTE_OPERATION_HIGH:if (paccu>0) accu[paccu-1]=(((int)floor(accu[paccu-1]+0.5))&0xFF00)>>8;break; - case E_COMPUTE_OPERATION_PSG:if (paccu>0) accu[paccu-1]=ae->psgfine[((int)floor(accu[paccu-1]+0.5))&0xFF];break; - case E_COMPUTE_OPERATION_RND:if (paccu>0) accu[paccu-1]=rand()%((int)accu[paccu-1]);break; - case E_COMPUTE_OPERATION_FRAC:if (paccu>0) accu[paccu-1]=modf(accu[paccu-1],&dummint);break; - case E_COMPUTE_OPERATION_CEIL:if (paccu>0) accu[paccu-1]=ceil(accu[paccu-1]);break; - case E_COMPUTE_OPERATION_GET_R:if (paccu>0) accu[paccu-1]=((((int)accu[paccu-1])&0xF0)>>4);break; - case E_COMPUTE_OPERATION_GET_V:if (paccu>0) accu[paccu-1]=((((int)accu[paccu-1])&0xF00)>>8);break; - case E_COMPUTE_OPERATION_GET_B:if (paccu>0) accu[paccu-1]=(((int)accu[paccu-1])&0xF);break; - case E_COMPUTE_OPERATION_SET_R:if (paccu>0) accu[paccu-1]=MinMaxInt(accu[paccu-1],0,15)<<4;break; - case E_COMPUTE_OPERATION_SET_V:if (paccu>0) accu[paccu-1]=MinMaxInt(accu[paccu-1],0,15)<<8;break; - case E_COMPUTE_OPERATION_SET_B:if (paccu>0) accu[paccu-1]=MinMaxInt(accu[paccu-1],0,15);break; - default:MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"invalid computing state! (%d)\n",GetExpFile(ae,didx),GetExpLine(ae,didx),computestack[i].operator);paccu=0; - } - if (!paccu) { - if (zeexpression[0]=='&') { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Missing operand for calculation [%s] Did you use & for an hexadecimal value?\n",TradExpression(zeexpression)); - } else { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Missing operand for calculation [%s]\n",TradExpression(zeexpression)); - } - accu_err=1; - break; - } - } - } - if (!original) { - MemFree(zeexpression); - } - if (paccu==1) { - return accu[0]; - } else if (!accu_err) { - if (paccu) { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Missing operator\n"); - } else { - MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Missing operand for calculation\n"); - } - return 0; - } else { - return 0; - } -} -int RoundComputeExpressionCore(struct s_assenv *ae,char *zeexpression,int ptr,int didx) { - return floor(ComputeExpressionCore(ae,zeexpression,ptr,didx)+ae->rough); -} - -void ExpressionSetDicoVar(struct s_assenv *ae,char *name, double v) -{ - #undef FUNC - #define FUNC "ExpressionSetDicoVar" - - struct s_expr_dico curdic; - curdic.name=TxtStrDup(name); - curdic.crc=GetCRC(name); - curdic.v=v; - curdic.iw=ae->idx; - curdic.autorise_export=ae->autorise_export; - //ObjectArrayAddDynamicValueConcat((void**)&ae->dico,&ae->idic,&ae->mdic,&curdic,sizeof(curdic)); - if (SearchLabel(ae,curdic.name,curdic.crc)) { - MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"cannot create variable [%s] as there is already a label with the same name\n",name); - MemFree(curdic.name); - return; - } - InsertDicoToTree(ae,&curdic); -} - -double ComputeExpression(struct s_assenv *ae,char *expr, int ptr, int didx, int expected_eval) -{ - #undef FUNC - #define FUNC "ComputeExpression" - - char *ptr_exp,*ptr_exp2,backupeval; - int crc,idic,idx=0,ialias,touched,hasformula=0; - double v,vl; - struct s_alias curalias; - struct s_expr_dico *curdic; - char *minibuffer; - - while (!ae->AutomateExpressionDecision[((int)expr[idx])&0xFF]) idx++; - - switch (ae->AutomateExpressionDecision[((int)expr[idx])&0xFF]) { - /***************************************** - M A K E A L I A S - *****************************************/ - case '~': - memset(&curalias,0,sizeof(curalias)); - ptr_exp=expr+idx; - *ptr_exp=0; // on scinde l'alias de son texte - ptr_exp2=ptr_exp+1; -#if TRACE_COMPUTE_EXPRESSION -printf("MakeAlias (1) EXPR=[%s EQU %s]\n",expr,ptr_exp2); -#endif - - /* alias locaux ou de proximité */ - if (strchr("@.",expr[0])) { -#if TRACE_COMPUTE_EXPRESSION -printf("WARNING! alias is local! [%s]\n",expr); -#endif - /* local label creation does not handle formula in tags */ - curalias.alias=TranslateTag(ae,TxtStrDup(expr),&touched,0,E_TAGOPTION_NONE); - curalias.alias=MakeLocalLabel(ae,curalias.alias,NULL); - hasformula=1; - } else if (strchr(expr,'{')) { -#if TRACE_COMPUTE_EXPRESSION -printf("WARNING! alias has tag! [%s]\n",expr); -#endif - /* alias name contains formula */ - curalias.alias=TranslateTag(ae,TxtStrDup(expr),&touched,0,E_TAGOPTION_NONE); -#if TRACE_COMPUTE_EXPRESSION -printf("MakeAlias (2) EXPR=[%s EQU %s]\n",expr,ptr_exp2); -#endif - hasformula=1; - } else { - curalias.alias=TxtStrDup(expr); - } - curalias.crc=GetCRC(curalias.alias); - if ((ialias=SearchAlias(ae,curalias.crc,curalias.alias))>=0) { - MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"Duplicate alias [%s]\n",expr); - MemFree(curalias.alias); - } else if (SearchDico(ae,curalias.alias,curalias.crc)) { - MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"Alias cannot override existing variable [%s]\n",expr); - MemFree(curalias.alias); - } else { - curalias.translation=MemMalloc(strlen(ptr_exp2)+1+2); - sprintf(curalias.translation,"(%s)",ptr_exp2); -#if TRACE_COMPUTE_EXPRESSION -printf("MakeAlias (3) EXPR=[%s EQU %s]\n",expr,ptr_exp2); -printf("alias translation [%s] -> ",curalias.translation);fflush(stdout); -#endif - ExpressionFastTranslate(ae,&curalias.translation,2); // FAST type 2 -#if TRACE_COMPUTE_EXPRESSION -printf("%s\n",curalias.translation); -#endif - curalias.len=strlen(curalias.translation); - curalias.autorise_export=ae->autorise_export; - curalias.iw=ae->idx; - ObjectArrayAddDynamicValueConcat((void**)&ae->alias,&ae->ialias,&ae->malias,&curalias,sizeof(curalias)); - CheckAndSortAliases(ae); - } - *ptr_exp='~'; // on remet l'alias en place -#if TRACE_COMPUTE_EXPRESSION -printf("MakeAlias end with alias=[%s]=[%s]\n",curalias.alias,curalias.translation); -printf("***********\n"); -#endif - return 0; - /***************************************** - S E T V A R - *****************************************/ - case '=': - /* patch NOT - this is a variable assign if there is no other comparison operator after '=' - BUT we may have ! which stand for NOT but is also a comparison operator... - */ - if (ae->AutomateExpressionDecision[((int)expr[idx+1])&0xFF]==0 || expr[idx+1]=='!') { - if (expected_eval) { - if (ae->maxam) { - /* maxam mode AND expected a value -> force comparison */ - } else { - /* use of a single '=' but expected a comparison anyway */ - MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"meaningless use of an expression [%s]\n",expr); - return 0; - } - } else { - /* ASSIGN */ - if ((expr[0]<'A' || expr[0]>'Z') && expr[0]!='_') { - MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"variable name must begin by a letter or '_' [%s]\n",expr); - return 0; - } else { - char operatorassignment; - - ptr_exp=expr+idx; - v=ComputeExpressionCore(ae,ptr_exp+1,ptr,didx); - *ptr_exp=0; - /* patch operator+assign value */ - switch (ptr_exp[-1]) { - case '+': - case '-': - case '*': - case '/': - case '^': - case '&': - case '|': - case '%': - case ']': - case '[': - operatorassignment=ptr_exp[-1];ptr_exp[-1]=0;break; - default:operatorassignment=0;break; - } - - crc=GetCRC(expr); - if ((ialias=SearchAlias(ae,crc,expr))>=0) { - MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"Variable cannot override existing alias [%s]\n",expr); - return 0; - } -#if TRACE_ASSEMBLE - printf("try to set [%s] with %lf operatorassignment=%c\n",expr,v,operatorassignment); -#endif - curdic=SearchDico(ae,expr,crc); - if (curdic) { - switch (operatorassignment) { - default:printf("warning remover\n"); - case 0:curdic->v=v;break; - case '+':curdic->v+=v;ptr_exp[-1]='+';break; - case '-':curdic->v-=v;ptr_exp[-1]='-';break; - case '*':curdic->v*=v;ptr_exp[-1]='*';break; - case '/':curdic->v/=v;ptr_exp[-1]='/';break; - /* bit operations */ - case '|':curdic->v=((int)curdic->v)|((int)v);ptr_exp[-1]='|';break; - case '&':curdic->v=((int)curdic->v)&((int)v);ptr_exp[-1]='&';break; - case '^':curdic->v=((int)curdic->v)^((int)v);ptr_exp[-1]='^';break; - case '%':curdic->v=((int)curdic->v)%((int)v);ptr_exp[-1]='%';break; - case ']':curdic->v=((int)curdic->v)>>((int)v);ptr_exp[-1]=']'; - if (v>31 || v<-31) { - if (!ae->nowarning) { - rasm_printf(ae,KWARNING"Warning - shifting %d is architecture dependant, result forced to ZERO\n",(int)v); - } - curdic->v=0; - } - break; - case '[':curdic->v=((int)curdic->v)<<((int)v);ptr_exp[-1]='['; - if (v>31 || v<-31) { - if (!ae->nowarning) { - rasm_printf(ae,KWARNING"Warning - shifting %d is architecture dependant, result forced to ZERO\n",(int)v); - } - curdic->v=0; - } - break; - } - } else { - switch (operatorassignment) { - default: /* cannot do operator on non existing variable */ - MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"Cannot do an operator assignment on non existing variable [%s]\n",expr); - return 0; - case 0: /* assign a new variable */ - ExpressionSetDicoVar(ae,expr,v); - break; - } - } - *ptr_exp='='; - return v; - } - } - } - break; - /***************************************** - P U R E E X P R E S S I O N - *****************************************/ - default:break; - } -#if TRACE_ASSEMBLE -printf("pure expression to compute [%s]\n",expr); -#endif - return ComputeExpressionCore(ae,expr,ptr,didx); -} -int RoundComputeExpression(struct s_assenv *ae,char *expr, int ptr, int didx, int expression_expected) { - return floor(ComputeExpression(ae,expr,ptr,didx,expression_expected)+ae->rough); -} - -/* - ExpressionFastTranslate - - purpose: translate all known symbols in an expression (especially variables acting like counters) -*/ -void ExpressionFastTranslate(struct s_assenv *ae, char **ptr_expr, int fullreplace) -{ - #undef FUNC - #define FUNC "ExpressionFastTranslate" - - struct s_label *curlabel; - struct s_expr_dico *curdic; - static char *varbuffer=NULL; - static int ivar=0,maxivar=1; - char curval[256]={0}; - int c,lenw=0,idx=0,crc,startvar,newlen,ialias,found_replace,yves,dek,reidx,lenbuf,rlen,tagoffset; - double v; - char tmpuchar[16]; - char *expr,*locallabel; - int curly=0,curlyflag=0; - char *Automate; - int recurse=-1,recursecount=0; - - if (!ae || !ptr_expr) { - if (varbuffer) MemFree(varbuffer); - varbuffer=NULL; - maxivar=1; - ivar=0; - return; - } - /* be sure to have at least some bytes allocated */ - StateMachineResizeBuffer(&varbuffer,128,&maxivar); - expr=*ptr_expr; - -//printf("fast [%s]\n",expr); - - while (!ae->AutomateExpressionDecision[((int)expr[idx])&0xFF]) idx++; - - switch (ae->maxam) { - default: - case 0: /* full check */ - if (expr[idx]=='~' || (expr[idx]=='=' && expr[idx+1]!='=')) {reidx=idx+1;break;} - reidx=0; - break; - case 1: /* partial check with maxam */ - if (expr[idx]=='~') {reidx=idx+1;break;} - reidx=0; - break; - } - - idx=0; - /* is there ascii char? */ - while ((c=expr[idx])!=0) { - if (c=='\'' || c=='"') { - /* echappement */ - if (expr[idx+1]=='\\') { - if (expr[idx+2] && expr[idx+3]==c) { - /* no charset conversion for escaped chars */ - c=expr[idx+2]; - switch (c) { - case 'b':c='\b';break; - case 'v':c='\v';break; - case 'f':c='\f';break; - case '0':c='\0';break; - case 'r':c='\r';break; - case 'n':c='\n';break; - case 't':c='\t';break; - default:break; - } - sprintf(tmpuchar,"#%03X",c); - memcpy(expr+idx,tmpuchar,4); - idx+=3; - } else { - MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"expression [%s] - Only single escaped char may be quoted\n",expr); - expr[0]=0; - return; - } - } else if (expr[idx+1] && expr[idx+2]==c) { - sprintf(tmpuchar,"#%02X",ae->charset[(int)expr[idx+1]]); - memcpy(expr+idx,tmpuchar,3); - idx+=2; - } else { - MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"expression [%s] - Only single char may be quoted\n",expr); - expr[0]=0; - return; - } - } - idx++; - } - - idx=reidx; - while ((c=expr[idx])!=0) { - switch (c) { - /* operator / parenthesis */ - case '!': - case '=': - case '>': - case '<': - case '(': - case ')': - case ']': - case '[': - case '*': - case '/': - case '+': - case '~': - case '-': - case '^': - case 'm': - case '|': - case '&': - idx++; - break; - default: - startvar=idx; - if (ae->AutomateExpressionValidCharFirst[((int)c)&0xFF]) { - varbuffer[ivar++]=c; - if (c=='{') { - /* this is only tag and not a formula */ - curly++; - } - StateMachineResizeBuffer(&varbuffer,ivar,&maxivar); - idx++; - c=expr[idx]; - - Automate=ae->AutomateExpressionValidChar; - while (Automate[((int)c)&0xFF]) { - if (c=='{') { - curly++; - curlyflag=1; - Automate=ae->AutomateExpressionValidCharExtended; - } else if (c=='}') { - curly--; - if (!curly) { - Automate=ae->AutomateExpressionValidChar; - } - } - varbuffer[ivar++]=c; - StateMachineResizeBuffer(&varbuffer,ivar,&maxivar); - idx++; - c=expr[idx]; - } - } - varbuffer[ivar]=0; - if (!ivar) { - MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"invalid expression [%s] c=[%c] idx=%d\n",expr,c,idx); - return; - } else if (curly) { - MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"wrong curly brackets in expression [%s]\n",expr); - return; - } - } - if (ivar && (varbuffer[0]<'0' || varbuffer[0]>'9')) { - /* numbering var or label */ - if (curlyflag) { - char *minivarbuffer; - int touched; -//printf("ExpressionFastTranslate curly\n"); - minivarbuffer=TranslateTag(ae,TxtStrDup(varbuffer), &touched,0,E_TAGOPTION_NONE|(fullreplace?0:E_TAGOPTION_PRESERVE)); - StateMachineResizeBuffer(&varbuffer,strlen(minivarbuffer)+1,&maxivar); - strcpy(varbuffer,minivarbuffer); - newlen=strlen(varbuffer); - lenw=strlen(expr); - /* must update source */ - if (newlen>ivar) { - /* realloc bigger */ - expr=*ptr_expr=MemRealloc(expr,lenw+newlen-ivar+1); - } - if (newlen!=ivar ) { - lenw=strlen(expr); - MemMove(expr+startvar+newlen,expr+startvar+ivar,lenw-startvar-ivar+1); - } - strncpy(expr+startvar,minivarbuffer,newlen); /* copy without zero terminator */ - idx=startvar+newlen; - /***/ - MemFree(minivarbuffer); - curlyflag=0; - /******* ivar must be updated in case of label or alias following ***********/ - ivar=newlen; - } - - /* recherche dans dictionnaire et remplacement */ - crc=GetCRC(varbuffer); - found_replace=0; - /* pour les affectations ou les tests conditionnels on ne remplace pas le dico (pour le Push oui par contre!) */ - if (fullreplace) { - if (varbuffer[0]=='$' && !varbuffer[1]) { - #ifdef OS_WIN - snprintf(curval,sizeof(curval)-1,"%d",ae->codeadr); - newlen=strlen(curval); - #else - newlen=snprintf(curval,sizeof(curval)-1,"%d",ae->codeadr); - #endif - lenw=strlen(expr); - if (newlen>ivar) { - /* realloc bigger */ - expr=*ptr_expr=MemRealloc(expr,lenw+newlen-ivar+1); - } - if (newlen!=ivar ) { - MemMove(expr+startvar+newlen,expr+startvar+ivar,lenw-startvar-ivar+1); - found_replace=1; - } - strncpy(expr+startvar,curval,newlen); /* copy without zero terminator */ - idx=startvar+newlen; - ivar=0; - found_replace=1; - } else { - curdic=SearchDico(ae,varbuffer,crc); - if (curdic) { - v=curdic->v; -//printf("ExpressionFastTranslate (full) -> replace var (%s=%0.1lf)\n",varbuffer,v); - - #ifdef OS_WIN - snprintf(curval,sizeof(curval)-1,"%lf",v); - newlen=TrimFloatingPointString(curval); - #else - snprintf(curval,sizeof(curval)-1,"%lf",v); - newlen=TrimFloatingPointString(curval); - #endif - lenw=strlen(expr); - if (newlen>ivar) { - /* realloc bigger */ - expr=*ptr_expr=MemRealloc(expr,lenw+newlen-ivar+1); - } - if (newlen!=ivar ) { - MemMove(expr+startvar+newlen,expr+startvar+ivar,lenw-startvar-ivar+1); - } - strncpy(expr+startvar,curval,newlen); /* copy without zero terminator */ - idx=startvar+newlen; - ivar=0; - found_replace=1; - } - } - } - /* on cherche aussi dans les labels existants */ - if (!found_replace) { - curlabel=SearchLabel(ae,varbuffer,crc); - if (curlabel) { - if (!curlabel->lz || ae->stage>1) { - yves=curlabel->ptr; - - #ifdef OS_WIN - snprintf(curval,sizeof(curval)-1,"%d",yves); - newlen=strlen(curval); - #else - newlen=snprintf(curval,sizeof(curval)-1,"%d",yves); - #endif - lenw=strlen(expr); - if (newlen>ivar) { - /* realloc bigger */ - expr=*ptr_expr=MemRealloc(expr,lenw+newlen-ivar+1); - } - if (newlen!=ivar ) { - MemMove(expr+startvar+newlen,expr+startvar+ivar,lenw-startvar-ivar+1); - } - strncpy(expr+startvar,curval,newlen); /* copy without zero terminator */ - found_replace=1; - idx=startvar+newlen; - ivar=0; - } - } - } - /* non trouve on cherche dans les alias */ - if (!found_replace) { - if ((ialias=SearchAlias(ae,crc,varbuffer))>=0) { - newlen=ae->alias[ialias].len; - lenw=strlen(expr); - /* infinite replacement check */ - if (recurse<=startvar) { - /* recurse maximum count is a mix of alias len and alias number */ - if (recursecount>ae->ialias+ae->alias[ialias].len) { - if (strchr(expr,'~')!=NULL) *strchr(expr,'~')=0; - MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"alias definition of %s has infinite recursivity\n",expr); - expr[0]=0; /* avoid some errors due to shitty definition */ - return; - } else { - recursecount++; - } - } - if (newlen>ivar) { - /* realloc bigger */ - expr=*ptr_expr=MemRealloc(expr,lenw+newlen-ivar+1); - } - if (newlen!=ivar) { - MemMove(expr+startvar+newlen,expr+startvar+ivar,lenw-startvar-ivar+1); - } - strncpy(expr+startvar,ae->alias[ialias].translation,newlen); /* copy without zero terminator */ - found_replace=1; - /* need to parse again alias because of delayed declarations */ - recurse=startvar; - idx=startvar; - ivar=0; - } else { - } - } - if (!found_replace) { - //printf("fasttranslate test local label\n"); - /* non trouve c'est peut-etre un label local - mais pas de l'octal */ - if (varbuffer[0]=='@' && (varbuffer[1]<'0' || varbuffer[1]>'9')) { - char *zepoint; - lenbuf=strlen(varbuffer); -//printf("MakeLocalLabel(ae,varbuffer,&dek); (1)\n"); - locallabel=MakeLocalLabel(ae,varbuffer,&dek); -//printf("exprin =[%s] rlen=%d dek-lenbuf=%d\n",expr,rlen,dek-lenbuf); - /*** le grand remplacement ***/ - /* local to macro or loop */ - rlen=strlen(expr+startvar+lenbuf)+1; - expr=*ptr_expr=MemRealloc(expr,strlen(expr)+dek+1); - /* move end of expression in order to insert local ID */ - zepoint=strchr(varbuffer,'.'); - if (zepoint) { - /* far proximity access */ - int suffixlen,dotpos; - dotpos=(zepoint-varbuffer); - suffixlen=lenbuf-dotpos; - - MemMove(expr+startvar+dotpos+dek,expr+startvar+dotpos,rlen+suffixlen); - strncpy(expr+startvar+dotpos,locallabel,dek); - } else { - /* legacy */ - MemMove(expr+startvar+lenbuf+dek,expr+startvar+lenbuf,rlen); - strncpy(expr+startvar+lenbuf,locallabel,dek); - } - idx+=dek; - MemFree(locallabel); - found_replace=1; -//printf("exprout=[%s]\n",expr); - } else if (varbuffer[0]=='.' && (varbuffer[1]<'0' || varbuffer[1]>'9')) { - /* proximity label */ - lenbuf=strlen(varbuffer); -//printf("MakeLocalLabel(ae,varbuffer,&dek); (2)\n"); - locallabel=MakeLocalLabel(ae,varbuffer,&dek); - /*** le grand remplacement ***/ - rlen=strlen(expr+startvar+lenbuf)+1; - dek=strlen(locallabel); -//printf("exprin =[%s] rlen=%d dek-lenbuf=%d\n",expr,rlen,dek-lenbuf); - expr=*ptr_expr=MemRealloc(expr,strlen(expr)+dek-lenbuf+1); - MemMove(expr+startvar+dek,expr+startvar+lenbuf,rlen); - strncpy(expr+startvar,locallabel,dek); - idx+=dek-lenbuf; - MemFree(locallabel); -//printf("exprout=[%s]\n",expr); - -//@@TODO ajouter une recherche d'alias? - - } else if (varbuffer[0]=='{') { - if (strncmp(varbuffer,"{BANK}",6)==0 || strncmp(varbuffer,"{PAGE}",6)==0) tagoffset=6; else - if (strncmp(varbuffer,"{PAGESET}",9)==0) tagoffset=9; else - if (strncmp(varbuffer,"{SIZEOF}",8)==0) tagoffset=8; else - { - tagoffset=0; - MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"Unknown prefix tag\n"); - } - - if (varbuffer[tagoffset]=='@') { - char *zepoint; - startvar+=tagoffset; - lenbuf=strlen(varbuffer+tagoffset); -//printf("MakeLocalLabel(ae,varbuffer,&dek); (3)\n"); - locallabel=MakeLocalLabel(ae,varbuffer+tagoffset,&dek); - /*** le grand remplacement ***/ - rlen=strlen(expr+startvar+lenbuf)+1; - expr=*ptr_expr=MemRealloc(expr,strlen(expr)+dek+1); - /* move end of expression in order to insert local ID */ - zepoint=strchr(varbuffer,'.'); - if (zepoint) { - /* far proximity access */ - int suffixlen,dotpos; - dotpos=(zepoint-varbuffer); - suffixlen=lenbuf-dotpos; - - MemMove(expr+startvar+dotpos+dek,expr+startvar+dotpos,rlen+suffixlen); - strncpy(expr+startvar+dotpos,locallabel,dek); - } else { - /* legacy */ - MemMove(expr+startvar+lenbuf+dek,expr+startvar+lenbuf,rlen); - strncpy(expr+startvar+lenbuf,locallabel,dek); - } - idx+=dek; - MemFree(locallabel); - found_replace=1; - } else if (varbuffer[tagoffset]=='$') { - int tagvalue=-1; - if (strcmp(varbuffer,"{BANK}$")==0) { - if (ae->forcecpr) { - if (ae->activebank<32) { - tagvalue=ae->activebank; - } else { - MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"expression [%s] cannot use BANK $ in a temporary space!\n",TradExpression(expr)); - tagvalue=0; - } - } else if (ae->forcesnapshot) { - if (ae->activebankbankset[ae->activebank>>2]) { - tagvalue=ae->activebank+(ae->codeadr>>14); /* dans un bankset on tient compte de l'adresse */ - } else { - tagvalue=ae->activebank; - } - - } else { - MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"expression [%s] cannot use BANK $ in a temporary space!\n",TradExpression(expr)); - tagvalue=0; - } - } - } else if (strcmp(varbuffer,"{PAGE}$")==0) { - if (ae->activebankbankset[ae->activebank>>2]) { - tagvalue=ae->bankgate[(ae->activebank&0x1FC)+(ae->codeadr>>14)]; - } else { - tagvalue=ae->bankgate[ae->activebank]; - } - } else { - MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"expression [%s] cannot use PAGE $ in a temporary space!\n",TradExpression(expr)); - tagvalue=ae->activebank; - } - } else if (strcmp(varbuffer,"{PAGESET}$")==0) { - if (ae->activebanksetgate[ae->activebank]; - //if (ae->activebank>3) tagvalue=((ae->activebank>>2)-1)*8+0xC2; else tagvalue=0xC0; - } else { - MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"expression [%s] cannot use PAGESET $ in a temporary space!\n",TradExpression(expr)); - tagvalue=ae->activebank; - } - } - /* replace */ - #ifdef OS_WIN - snprintf(curval,sizeof(curval)-1,"%d",tagvalue); - newlen=strlen(curval); - #else - newlen=snprintf(curval,sizeof(curval)-1,"%d",tagvalue); - #endif - lenw=strlen(expr); - if (newlen>ivar) { - /* realloc bigger */ - expr=*ptr_expr=MemRealloc(expr,lenw+newlen-ivar+1); - } - if (newlen!=ivar ) { - MemMove(expr+startvar+newlen,expr+startvar+ivar,lenw-startvar-ivar+1); - found_replace=1; - } - strncpy(expr+startvar,curval,newlen); /* copy without zero terminator */ - idx=startvar+newlen; - ivar=0; - found_replace=1; - } - } - } - - - - - - - if (!found_replace && strcmp(varbuffer,"REPEAT_COUNTER")==0) { - if (ae->ir) { - yves=ae->repeat[ae->ir-1].repeat_counter; - #ifdef OS_WIN - snprintf(curval,sizeof(curval)-1,"%d",yves); - newlen=strlen(curval); - #else - newlen=snprintf(curval,sizeof(curval)-1,"%d",yves); - #endif - lenw=strlen(expr); - if (newlen>ivar) { - /* realloc bigger */ - expr=*ptr_expr=MemRealloc(expr,lenw+newlen-ivar+1); - } - if (newlen!=ivar ) { - MemMove(expr+startvar+newlen,expr+startvar+ivar,lenw-startvar-ivar+1); - found_replace=1; - } - strncpy(expr+startvar,curval,newlen); /* copy without zero terminator */ - found_replace=1; - idx=startvar+newlen; - ivar=0; - } else { - MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"cannot use REPEAT_COUNTER outside repeat loop\n"); - } - } - if (!found_replace && strcmp(varbuffer,"WHILE_COUNTER")==0) { - if (ae->iw) { - yves=ae->whilewend[ae->iw-1].while_counter; - #ifdef OS_WIN - snprintf(curval,sizeof(curval)-1,"%d",yves); - newlen=strlen(curval); - #else - newlen=snprintf(curval,sizeof(curval)-1,"%d",yves); - #endif - lenw=strlen(expr); - if (newlen>ivar) { - /* realloc bigger */ - expr=*ptr_expr=MemRealloc(expr,lenw+newlen-ivar+1); - } - if (newlen!=ivar ) { - MemMove(expr+startvar+newlen,expr+startvar+ivar,lenw-startvar-ivar+1); - found_replace=1; - } - strncpy(expr+startvar,curval,newlen); /* copy without zero terminator */ - found_replace=1; - idx=startvar+newlen; - ivar=0; - } else { - MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"cannot use WHILE_COUNTER outside repeat loop\n"); - } - } - /* unknown symbol -> add to used symbol pool */ - if (!found_replace) { - InsertUsedToTree(ae,varbuffer,crc); - } - } - ivar=0; - } -} - -void PushExpression(struct s_assenv *ae,int iw,enum e_expression zetype) -{ - #undef FUNC - #define FUNC "PushExpression" - - struct s_expression curexp={0}; - int startptr=0; - - if (!ae->nocode) { - curexp.iw=iw; - curexp.wptr=ae->outputadr; - curexp.zetype=zetype; - curexp.ibank=ae->activebank; - curexp.iorgzone=ae->io-1; - curexp.lz=ae->lz; - /* on traduit de suite les variables du dictionnaire pour les boucles et increments - SAUF si c'est une affectation */ - if (!ae->wl[iw].e) { - switch (zetype) { - case E_EXPRESSION_V16C: - /* check non register usage */ - switch (GetCRC(ae->wl[iw].w)) { - case CRC_IX: - case CRC_IY: - case CRC_MIX: - case CRC_MIY: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"invalid register usage\n",ae->maxptr); - default:break; - } - case E_EXPRESSION_J8: - case E_EXPRESSION_V8: - case E_EXPRESSION_V16: - case E_EXPRESSION_IM:startptr=-1; - break; - case E_EXPRESSION_IV8: - case E_EXPRESSION_IV81: - case E_EXPRESSION_IV16:startptr=-2; - break; - case E_EXPRESSION_3V8:startptr=-3; - break; - case E_EXPRESSION_RUN: - case E_EXPRESSION_ZXRUN: - case E_EXPRESSION_ZXSTACK: - case E_EXPRESSION_BRS:break; - default:break; - } - /* hack pourri pour gérer le $ */ - ae->codeadr+=startptr; - /* ok mais les labels locaux des macros? */ - if (ae->ir || ae->iw || ae->imacro) { - curexp.reference=TxtStrDup(ae->wl[iw].w); - ExpressionFastTranslate(ae,&curexp.reference,1); - } else { - ExpressionFastTranslate(ae,&ae->wl[iw].w,1); - } - ae->codeadr-=startptr; - } - /* calcul adresse de reference et post-incrementation pour sauter les data */ - switch (zetype) { - case E_EXPRESSION_J8:curexp.ptr=ae->codeadr-1;ae->outputadr++;ae->codeadr++;break; - case E_EXPRESSION_0V8:curexp.ptr=ae->codeadr;ae->outputadr++;ae->codeadr++;break; - case E_EXPRESSION_V8:curexp.ptr=ae->codeadr-1;ae->outputadr++;ae->codeadr++;break; - case E_EXPRESSION_0V16:curexp.ptr=ae->codeadr;ae->outputadr+=2;ae->codeadr+=2;break; - case E_EXPRESSION_0V32:curexp.ptr=ae->codeadr;ae->outputadr+=4;ae->codeadr+=4;break; - case E_EXPRESSION_0VR:curexp.ptr=ae->codeadr;ae->outputadr+=5;ae->codeadr+=5;break; - case E_EXPRESSION_V16C: - case E_EXPRESSION_V16:curexp.ptr=ae->codeadr-1;ae->outputadr+=2;ae->codeadr+=2;break; - case E_EXPRESSION_IV81:curexp.ptr=ae->codeadr-2;ae->outputadr++;ae->codeadr++;break; - case E_EXPRESSION_IV8:curexp.ptr=ae->codeadr-2;ae->outputadr++;ae->codeadr++;break; - case E_EXPRESSION_3V8:curexp.ptr=ae->codeadr-3;ae->outputadr++;ae->codeadr++;break; - case E_EXPRESSION_IV16:curexp.ptr=ae->codeadr-2;ae->outputadr+=2;ae->codeadr+=2;break; - case E_EXPRESSION_RST:curexp.ptr=ae->codeadr;ae->outputadr++;ae->codeadr++;break; - case E_EXPRESSION_IM:curexp.ptr=ae->codeadr-1;ae->outputadr++;ae->codeadr++;break; - case E_EXPRESSION_RUN:break; - case E_EXPRESSION_ZXRUN:break; - case E_EXPRESSION_ZXSTACK:break; - case E_EXPRESSION_BRS:curexp.ptr=ae->codeadr;break; // minimum syndical - default:break; - } - /* le contrôle n'est pas bon avec les DEFB, DEFW, ... -> @@TODO */ - if (ae->outputadr<=ae->maxptr) { - ObjectArrayAddDynamicValueConcat((void **)&ae->expression,&ae->ie,&ae->me,&curexp,sizeof(curexp)); - } else { - /* to avoid double error message */ - if (!ae->stop) MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"output exceed limit %d\n",ae->maxptr); else MaxError(ae); - ae->stop=1; - return; - } - } else { - switch (zetype) { - case E_EXPRESSION_J8:ae->outputadr++;ae->codeadr++;break; - case E_EXPRESSION_0V8:ae->outputadr++;ae->codeadr++;break; - case E_EXPRESSION_V8:ae->outputadr++;ae->codeadr++;break; - case E_EXPRESSION_0V16:ae->outputadr+=2;ae->codeadr+=2;break; - case E_EXPRESSION_0V32:ae->outputadr+=4;ae->codeadr+=4;break; - case E_EXPRESSION_0VR:ae->outputadr+=5;ae->codeadr+=5;break; - case E_EXPRESSION_V16C: - case E_EXPRESSION_V16:ae->outputadr+=2;ae->codeadr+=2;break; - case E_EXPRESSION_IV81:ae->outputadr++;ae->codeadr++;break; - case E_EXPRESSION_IV8:ae->outputadr++;ae->codeadr++;break; - case E_EXPRESSION_3V8:ae->outputadr++;ae->codeadr++;break; - case E_EXPRESSION_IV16:ae->outputadr+=2;ae->codeadr+=2;break; - case E_EXPRESSION_RST:ae->outputadr++;ae->codeadr++;break; - case E_EXPRESSION_IM:ae->outputadr++;ae->codeadr++;break; - case E_EXPRESSION_RUN:break; - case E_EXPRESSION_ZXRUN:break; - case E_EXPRESSION_ZXSTACK:break; - case E_EXPRESSION_BRS:break; - } - if (ae->outputadr<=ae->maxptr) { - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"NOCODE output exceed limit %d\n",GetCurrentFile(ae),ae->wl[ae->idx].l,ae->maxptr); - FreeAssenv(ae);exit(3); - } - } -} - -/* -The CP/M 2.2 directory has only one type of entry: - -UU F1 F2 F3 F4 F5 F6 F7 F8 T1 T2 T3 EX S1 S2 RC .FILENAMETYP.... -AL AL AL AL AL AL AL AL AL AL AL AL AL AL AL AL ................ - -UU = User number. 0-15 (on some systems, 0-31). The user number allows multiple - files of the same name to coexist on the disc. - User number = 0E5h => File deleted -Fn - filename -Tn - filetype. The characters used for these are 7-bit ASCII. - The top bit of T1 (often referred to as T1') is set if the file is - read-only. - T2' is set if the file is a system file (this corresponds to "hidden" on - other systems). -EX = Extent counter, low byte - takes values from 0-31 -S2 = Extent counter, high byte. - - An extent is the portion of a file controlled by one directory entry. - If a file takes up more blocks than can be listed in one directory entry, - it is given multiple entries, distinguished by their EX and S2 bytes. The - formula is: Entry number = ((32*S2)+EX) / (exm+1) where exm is the - extent mask value from the Disc Parameter Block. - -S1 - reserved, set to 0. -RC - Number of records (1 record=128 bytes) used in this extent, low byte. - The total number of records used in this extent is - - (EX & exm) * 128 + RC - - If RC is 80h, this extent is full and there may be another one on the disc. - File lengths are only saved to the nearest 128 bytes. - -AL - Allocation. Each AL is the number of a block on the disc. If an AL - number is zero, that section of the file has no storage allocated to it - (ie it does not exist). For example, a 3k file might have allocation - 5,6,8,0,0.... - the first 1k is in block 5, the second in block 6, the - third in block 8. - AL numbers can either be 8-bit (if there are fewer than 256 blocks on the - disc) or 16-bit (stored low byte first). -*/ -int EDSK_getblockid(int *fb) { - #undef FUNC - #define FUNC "EDSK_getblockid" - - int i; - for (i=0;i<180;i++) { - if (fb[i]) { - return i; - } - } - return -1; -} -int EDSK_getdirid(struct s_edsk_wrapper *curwrap) { - #undef FUNC - #define FUNC "EDSK_getdirid" - - int ie; - for (ie=0;ie<64;ie++) { - if (curwrap->entry[ie].user==0xE5) { -#if TRACE_EDSK - printf("getdirid returns %d\n",ie); -#endif - return ie; - } - } - return -1; -} -char *MakeAMSDOS_name(struct s_assenv *ae, char *filename) -{ - #undef FUNC - #define FUNC "MakeAMSDOS_name" - - static char amsdos_name[12]; - int i,ia; - char *pp; - /* warning */ - if (strlen(filename)>12) { - if (!ae->nowarning) rasm_printf(ae,KWARNING"Warning - filename [%s] too long for AMSDOS, will be truncated\n",filename); - } else if ((pp=strchr(filename,'.'))!=NULL) { - if (pp-filename>8) { - if (!ae->nowarning) rasm_printf(ae,KWARNING"Warning - filename [%s] too long for AMSDOS, will be truncated\n",filename); - } - } - /* copy filename */ - for (i=0;filename[i]!=0 && filename[i]!='.' && i<8;i++) { - amsdos_name[i]=toupper(filename[i]); - } - /* fill with spaces */ - for (ia=i;ia<8;ia++) { - amsdos_name[ia]=0x20; - } - /* looking for extension */ - for (;filename[i]!=0 && filename[i]!='.';i++); - /* then copy it if any */ - if (filename[i]=='.') { - i++; - for (ia=0;filename[i]!=0 && ia<3;ia++) { - amsdos_name[8+ia]=toupper(filename[i++]); - } - } - amsdos_name[11]=0; -#if TRACE_EDSK - printf("MakeAMSDOS_name [%s] -> [%s]\n",filename,amsdos_name); -#endif - return amsdos_name; -} - - -void EDSK_load(struct s_assenv *ae,struct s_edsk_wrapper *curwrap, char *edskfilename, int face) -{ - #undef FUNC - #define FUNC "EDSK_load" - - unsigned char header[256]; - unsigned char *data; - int tracknumber,sidenumber,tracksize,disksize; - int i,b,s,f,t,curtrack,sectornumber,sectorsize,sectorid,reallength; - int currenttrackposition=0,currentsectorposition,tmpcurrentsectorposition; - unsigned char checksectorid[9]; - int curblock=0,curoffset=0; -#if TRACE_EDSK - printf("EDSK_Load('%s',%d);",edskfilename,face); -#endif - if (FileReadBinary(edskfilename,(char*)&header,0x100)!=0x100) { - rasm_printf(ae,KERROR"Cannot read EDSK header of [%s]!\n",edskfilename); - FreeAssenv(ae);exit(ABORT_ERROR); - } - if (strncmp((char *)header,"MV - CPC",8)==0) { - rasm_printf(ae,KAYGREEN"updating DSK to EDSK [%s] / creator: %s",edskfilename,header+34); - - tracknumber=header[34+14]; - sidenumber=header[34+14+1]; - tracksize=header[34+14+1+1]+header[34+14+1+1+1]*256; - rasm_printf(ae,"tracks: %d sides:%d track size:%d",tracknumber,sidenumber,tracksize); - if (tracknumber>40 || sidenumber>2) { - rasm_printf(ae,KERROR"[%s] DSK format is not supported in update mode (ntrack=%d nside=%d)\n",edskfilename,tracknumber,sidenumber); - FreeAssenv(ae);exit(ABORT_ERROR); - } - if (face>=sidenumber) { - rasm_printf(ae,KWARNING"[%s] Warning - DSK has no face %d - DSK updated\n",edskfilename,face); - return; - } - - data=MemMalloc(tracksize*tracknumber*sidenumber); - memset(data,0,tracksize*tracknumber*sidenumber); - if (FileReadBinary(edskfilename,(char *)data,tracksize*tracknumber*sidenumber)!=tracksize*tracknumber*sidenumber) { - rasm_printf(ae,"Cannot read DSK tracks!"); - FreeAssenv(ae);exit(ABORT_ERROR); - } - //loginfo("track data read (%dkb)",tracksize*tracknumber*sidenumber/1024); - f=face; - for (t=0;t0xC9) { - rasm_printf(ae,"Invalid sector ID in sector %02X track %d",data[i+24+8*s+2],t); - FreeAssenv(ae);exit(ABORT_ERROR); - } else { - checksectorid[data[i+24+8*s+2]-0xC1]=1; - } - if (data[i+24+8*s+3]!=2) { - rasm_printf(ae,"Invalid sector size in sector %02X track %d",data[i+24+8*s+2],t); - FreeAssenv(ae);exit(ABORT_ERROR); - } - } - for (s=0;sblocks[curblock][curoffset],&data[i+0x100+s*512],512); - curoffset+=512; - if (curoffset>=1024) { - curoffset=0; - curblock++; - } - } - } - } - } else if (strncmp((char *)header,"EXTENDED",8)==0) { - rasm_printf(ae,KAYGREEN"updating EDSK [%s] / creator: %-14.14s\n",edskfilename,header+34); - tracknumber=header[34+14]; - sidenumber=header[34+14+1]; - // not in EDSK tracksize=header[34+14+1+1]+header[34+14+1+1+1]*256; -#if TRACE_EDSK - loginfo("tracks: %d sides:%d",tracknumber,sidenumber); -#endif - - if (sidenumber>2) { - rasm_printf(ae,KERROR"[%s] EDSK format is not supported in update mode (ntrack=%d nside=%d)\n",edskfilename,tracknumber,sidenumber); - FreeAssenv(ae);exit(ABORT_ERROR); - } - if (face>=sidenumber) { - rasm_printf(ae,KWARNING"[%s] EDSK has no face %d - DSK updated\n",edskfilename,face); - return; - } - - for (i=disksize=0;i=0xC1 && sectorid<=0xC9) checksectorid[sectorid-0xC1]=1; else { - rasm_printf(ae,KERROR"invalid sector id %02X for DATA track %d\n",sectorid,t); - return; - } - sectorsize=data[i+24+8*s+3]; - if (sectorsize!=2) { - rasm_printf(ae,KERROR"invalid sector size track %d\n",t); - return; - } - reallength=data[i+24+8*s+6]+data[i+24+8*s+7]*256; /* real length stored */ - if (reallength!=512) { - rasm_printf(ae,KERROR"invalid sector length %d for track %d\n",reallength,t); - return; - } -#if TRACE_EDSK - printf("%02X ",sectorid); -#endif - } - if (track_sectorsize!=2) { - rasm_printf(ae,KWARNING"track %02d has invalid sector size but sectors are OK\n",t); - } -#if TRACE_EDSK - printf("\n"); -#endif - - /* piste à piste on lit les blocs DANS L'ORDRE LOGIQUE!!! */ - for (b=0xC1;b<=0xC9;b++) { - tmpcurrentsectorposition=currentsectorposition; - for (s=0;sblocks[curblock][curoffset],&data[tmpcurrentsectorposition],512); - curoffset+=512; - if (curoffset>=1024) { - curoffset=0; - curblock++; - } - } - reallength=data[i+24+8*s+6]+data[i+24+8*s+7]*256; - tmpcurrentsectorposition+=reallength; - } - } - } - } - - - } else { - rasm_printf(ae,KERROR"file [%s] is not a valid (E)DSK floppy image\n",edskfilename); - FreeAssenv(ae);exit(-923); - } - FileReadBinaryClose(edskfilename); - - /* Rasm management of (e)DSK files is AMSDOS compatible, just need to copy CATalog blocks but sort them... */ - memcpy(&curwrap->entry[0],curwrap->blocks[0],1024); - memcpy(&curwrap->entry[32],curwrap->blocks[1],1024); - /* tri des entrées selon le user */ - qsort(curwrap->entry,64,sizeof(struct s_edsk_wrapper_entry),cmpAmsdosentry); - curwrap->nbentry=64; - for (i=0;i<64;i++) { - if (curwrap->entry[i].user==0xE5) { - curwrap->nbentry=i; - break; - } - } -#if TRACE_EDSK - printf("%d entr%s found\n",curwrap->nbentry,curwrap->nbentry>1?"ies":"y"); - for (i=0;inbentry;i++) { - printf("[%02d] - ",i); - if (curwrap->entry[i].user<16) { - printf("U%02d [%-8.8s.%c%c%c] %c%c subcpt=#%02X rc=#%02X blocks=",curwrap->entry[i].user,curwrap->entry[i].filename, - curwrap->entry[i].filename[8]&0x7F,curwrap->entry[i].filename[9]&0x7F,curwrap->entry[i].filename[10], - curwrap->entry[i].filename[8]&0x80?'P':'-',curwrap->entry[i].filename[9]&0x80?'H':'-', - curwrap->entry[i].subcpt,curwrap->entry[i].rc); - for (b=0;b<16;b++) if (curwrap->entry[i].blocks[b]) printf("%s%02X",b>0?" ":"",curwrap->entry[i].blocks[b]); else printf("%s ",b>0?" ":""); - if (i&1) printf("\n"); else printf(" | "); - } else { - printf("free entry = rc= blocks= "); - if (i&1) printf("\n"); else printf(" | "); - } - } - if (i&1) printf("\n"); -#endif -} - -struct s_edsk_wrapper *EDSK_select(struct s_assenv *ae,char *edskfilename, int facenumber) -{ - #undef FUNC - #define FUNC "EDSK_select" - - struct s_edsk_wrapper newwrap={0},*curwrap=NULL; - int i; -#if TRACE_EDSK - printf("EDSK_select('%s',%d);\n",edskfilename,facenumber); -#endif - /* check if there is a DSK in memory */ - for (i=0;inbedskwrapper;i++) { - if (!strcmp(ae->edsk_wrapper[i].edsk_filename,edskfilename)) { -#if TRACE_EDSK - printf("Found! return %d\n",i); -#endif - return &ae->edsk_wrapper[i]; - } - } - /* not in memory, create an empty struct */ - newwrap.edsk_filename=TxtStrDup(edskfilename); - memset(newwrap.entry,0xE5,sizeof(struct s_edsk_wrapper_entry)*64); - memset(newwrap.blocks[0],0xE5,1024); - memset(newwrap.blocks[1],0xE5,1024); -#if TRACE_EDSK - printf("Not found! create empty struct\n"); -#endif - newwrap.face=facenumber; - ObjectArrayAddDynamicValueConcat((void**)&ae->edsk_wrapper,&ae->nbedskwrapper,&ae->maxedskwrapper,&newwrap,sizeof(struct s_edsk_wrapper)); - /* and load files if the DSK exists on disk */ - curwrap=&ae->edsk_wrapper[ae->nbedskwrapper-1]; - if (FileExists(edskfilename)) { - EDSK_load(ae,curwrap,edskfilename,facenumber); - } - return curwrap; -} - -int EDSK_addfile(struct s_assenv *ae,char *edskfilename,int facenumber, char *filename,unsigned char *indata,int insize, int offset, int run) -{ - #undef FUNC - #define FUNC "EDSK_addfile" - - struct s_edsk_wrapper *curwrap=NULL; - char amsdos_name[12]={0}; - int j,i,ia,ib,ie,filesize,idxdata; - int fb[180],rc,idxb; - unsigned char *data=NULL; - int size=0; - int firstblock; - - curwrap=EDSK_select(ae,edskfilename,facenumber); - /* update struct */ - size=insize+128; - data=MemMalloc(size); - strcpy(amsdos_name,MakeAMSDOS_name(ae,filename)); - memcpy(data,MakeAMSDOSHeader(run,offset,offset+insize,amsdos_name),128); - memcpy(data+128,indata,insize); - /* overwrite check */ -#if TRACE_EDSK - printf("EDSK_addfile will checks %d entr%s for [%s]\n",curwrap->nbentry,curwrap->nbentry>1?"ies":"y",amsdos_name); -#endif - for (i=0;inbentry;i++) { - if (!strncmp((char *)curwrap->entry[i].filename,amsdos_name,11)) { - if (!ae->edskoverwrite) { - MakeError(ae,NULL,0,"Error - Cannot save [%s] in edsk [%s] with overwrite disabled as the file already exists\n",amsdos_name,edskfilename); - MemFree(data); - return 0; - } else { - /* overwriting previous file */ -#if TRACE_EDSK - printf(" -> reset previous entry %d with 0xE5\n",i); -#endif - memset(&curwrap->entry[i],0xE5,sizeof(struct s_edsk_wrapper_entry)); - } - } - } - /* find free blocks */ -#if TRACE_EDSK - printf("EDSK_addfile find free blocks\n"); -#endif - fb[0]=fb[1]=0; - for (i=2;i<180;i++) fb[i]=1; - for (i=0;inbentry;i++) { - if (curwrap->entry[i].rc!=0xE5 && curwrap->entry[i].rc!=0) { - /* entry found, compute number of blocks to read */ - rc=curwrap->entry[i].rc/8; - if (curwrap->entry[i].rc%8) rc++; /* adjust value */ - /* mark as used */ - for (j=0;jentry[i].blocks[j]]=0; - } - } - } - /* set directory, blocks and data in blocks */ - firstblock=-1; - filesize=size; - idxdata=0; - ia=0; - -#if TRACE_EDSK - printf("Writing [%s] size=%d\n",amsdos_name,size); -#endif - - while (filesize>0) { - if (filesize>16384) { - /* extended entry */ -#if TRACE_EDSK - printf("extended entry for file (filesize=%d)\nblocklist: ",filesize); -#endif - if ((ie=EDSK_getdirid(curwrap))==-1) { - MakeError(ae,NULL,0,"Error - edsk [%s] DIRECTORY FULL\n",edskfilename); - MemFree(data); - return 0; - } - if (curwrap->nbentry<=ie) curwrap->nbentry=ie+1; - idxb=0; - for (i=0;i<16;i++) { - if ((ib=EDSK_getblockid(fb))==-1) { - MakeError(ae,NULL,0,"Error - edsk [%s] DISK FULL\n",edskfilename); - MemFree(data); - return 0; - } else { - if (firstblock==-1) firstblock=ib; - -#if TRACE_EDSK - printf("%02X ",ib); -#endif - memcpy(curwrap->blocks[ib],data+idxdata,1024); - idxdata+=1024; - filesize-=1024; - fb[ib]=0; - curwrap->entry[ie].blocks[idxb++]=ib; - } - } -#if TRACE_EDSK - printf("\n"); -#endif - memcpy(curwrap->entry[ie].filename,amsdos_name,11); - curwrap->entry[ie].subcpt=ia; - curwrap->entry[ie].rc=0x80; - curwrap->entry[ie].user=0; - ia++; - idxb=0; - } else { - /* last entry */ -#if TRACE_EDSK - printf("last entry for file (filesize=%d)\nblocklist: ",filesize); -#endif - if ((ie=EDSK_getdirid(curwrap))==-1) { - MakeError(ae,NULL,0,"Error - edsk [%s] DIRECTORY FULL\n",edskfilename); - MemFree(data); - return 0; - } - if (curwrap->nbentry<=ie) curwrap->nbentry=ie+1; - /* calcul du nombre de sous blocs de 128 octets */ - curwrap->entry[ie].rc=filesize/128; - if (filesize%128) { - curwrap->entry[ie].rc+=1; - } - idxb=0; - for (i=0;i<16 && filesize>0;i++) { - if ((ib=EDSK_getblockid(fb))==-1) { - MakeError(ae,NULL,0,"Error - edsk [%s] DISK FULL\n",edskfilename); - MemFree(data); - return 0; - } else { - if (firstblock==-1) firstblock=ib; -#if TRACE_EDSK - printf("%02X ",ib); -#endif - - memcpy(curwrap->blocks[ib],&data[idxdata],filesize>1024?1024:filesize); - idxdata+=1024; - filesize-=1024; - fb[ib]=0; - curwrap->entry[ie].blocks[idxb++]=ib; - } - } -#if TRACE_EDSK - printf("\n"); -#endif - filesize=0; - memcpy(curwrap->entry[ie].filename,amsdos_name,11); - curwrap->entry[ie].subcpt=ia; - curwrap->entry[ie].user=0; - } - } - - MemFree(data); - return 1; -} - -void EDSK_build_amsdos_directory(struct s_edsk_wrapper *face) -{ - #undef FUNC - #define FUNC "EDSK_build_amsdos_directory" - - unsigned char amsdosdir[2048]={0}; - int i,idx=0,b; - - if (!face) return; - -#if TRACE_EDSK -printf("build amsdos dir with %d entries\n",face->nbentry); -#endif - for (i=0;inbentry;i++) { - if (face->entry[i].rc && face->entry[i].rc!=0xE5) { - amsdosdir[idx]=face->entry[i].user; - memcpy(amsdosdir+idx+1,face->entry[i].filename,11); - amsdosdir[idx+12]=face->entry[i].subcpt; - amsdosdir[idx+13]=0; - amsdosdir[idx+14]=0; - amsdosdir[idx+15]=face->entry[i].rc; -#if TRACE_EDSK -printf("%-11.11s [%02X.%02X] blocks:",amsdosdir+idx+1,amsdosdir[idx+12],amsdosdir[idx+15]); -#endif - for (b=0;b<16;b++) { - if (face->entry[i].blocks[b]!=0xE5) { - amsdosdir[idx+16+b]=face->entry[i].blocks[b]; -#if TRACE_EDSK - printf("%s%02X",b>0?".":"",amsdosdir[idx+16+b]); -#endif - } else { - amsdosdir[idx+16+b]=0; - } - } -#if TRACE_EDSK -printf("\n"); -#endif - } - idx+=32; - } -#if TRACE_EDSK -printf("filling amsdos remaining entries (%d) with #E5\n",64-face->nbentry); -#endif - memset(amsdosdir+idx,0xE5,32*(64-face->nbentry)); - - /* AMSDOS directory copy to blocks! */ - memcpy(face->blocks[0],amsdosdir,1024); - memcpy(face->blocks[1],amsdosdir+1024,1024); -} -void EDSK_write_file(struct s_assenv *ae,struct s_edsk_wrapper *faceA,struct s_edsk_wrapper *faceB) -{ - #undef FUNC - #define FUNC "EDSK_write_file" - - struct s_edsk_wrapper emptyface={0}; - unsigned char header[256]={0}; - unsigned char trackblock[256]={0}; - int idblock,blockoffset; - int i,t; - - if (!faceA && !faceB) return; - - /* création des deux blocs du directory par face */ - EDSK_build_amsdos_directory(faceA); - EDSK_build_amsdos_directory(faceB); - /* écriture header */ - strcpy((char *)header,"EXTENDED CPC DSK File\r\nDisk-Info\r\n"); - strcpy((char *)header+0x22,RASM_SNAP_VERSION); - header[0x30]=40; - if (!faceA) { - faceA=&emptyface; - faceA->edsk_filename=TxtStrDup(faceB->edsk_filename); - } -#if TRACE_EDSK - printf("deleting [%s]\n",faceA->edsk_filename); -#endif - FileRemoveIfExists(faceA->edsk_filename); - - if (faceB!=NULL) header[0x31]=2; else header[0x31]=1; - for (i=0;iedsk_filename,(char *)header,256); - - /* écriture des pistes */ - for (t=0;t<40;t++) { - strcpy((char *)trackblock,"Track-Info\r\n"); - trackblock[0x10]=t; - trackblock[0x11]=0; - trackblock[0x14]=2; - trackblock[0x15]=9; - trackblock[0x16]=0x4E; - trackblock[0x17]=0xE5; - i=0; - while (1) { - trackblock[0x18+i*8+0]=trackblock[0x10]; - trackblock[0x18+i*8+1]=trackblock[0x11]; - trackblock[0x18+i*8+2]=(i>>1)+0xC1; -#if TRACE_EDSK - if (t<3) printf("%02X ",trackblock[0x18+i*8+2]); -#endif - trackblock[0x18+i*8+3]=2; - trackblock[0x18+i*8+4]=0; - trackblock[0x18+i*8+5]=0; - trackblock[0x18+i*8+6]=0; - trackblock[0x18+i*8+7]=2; - i++; - if (i==9) break; - /* interleave */ - trackblock[0x18+i*8+0]=trackblock[0x10]; - trackblock[0x18+i*8+1]=trackblock[0x11]; - trackblock[0x18+i*8+2]=(i>>1)+0xC6; /* start at C6 */ -#if TRACE_EDSK - if (t<3) printf("%02X ",trackblock[0x18+i*8+2]); -#endif - trackblock[0x18+i*8+3]=2; - trackblock[0x18+i*8+4]=0; - trackblock[0x18+i*8+5]=0; - trackblock[0x18+i*8+6]=0; - trackblock[0x18+i*8+7]=2; - i++; - } -#if TRACE_EDSK - if (t<3) printf("\n"); else if (t==3) printf("...\n"); -#endif - /* écriture du track info */ - FileWriteBinary(faceA->edsk_filename,(char *)trackblock,256); - - - /* il faut convertir les blocs logiques en secteurs physiques ET entrelacés */ - idblock=t*9/2; - blockoffset=((t*9)%2)*512; - - /* le premier secteur de la piste est à cheval sur le bloc logique une fois sur deux */ - FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock][0]+blockoffset,512); /* C1 */ - if (!blockoffset) { - FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+2][0]+512,512); /* C6 */ - FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+0][0]+512,512); /* C2 */ - FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+3][0]+0,512); /* C7 */ - FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+1][0]+0,512); /* C3 */ - FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+3][0]+512,512); /* C8 */ - FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+1][0]+512,512); /* C4 */ - FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+4][0]+0,512); /* C9 */ - FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+2][0]+0,512); /* C5 */ - } else { - FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+3][0]+0,512); /* C6 */ - FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+1][0]+0,512); /* C2 */ - FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+3][0]+512,512); /* C7 */ - FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+1][0]+512,512); /* C3 */ - FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+4][0]+0,512); /* C8 */ - FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+2][0]+0,512); /* C4 */ - FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+4][0]+512,512); /* C9 */ - FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+2][0]+512,512); /* C5 */ - } - - /* @@TODO ça semble un peu foireux comme procédé */ - if (faceB) { -#if TRACE_EDSK - printf("writing EDSK face B /!\\ probably NOT WORKING !!!\n"); -#endif - trackblock[0x11]=1; - for (i=0;i<9;i++) { - trackblock[0x18+i*8+0]=trackblock[0x10]; - trackblock[0x18+i*8+1]=trackblock[0x11]; - } - /* écriture du track info */ - FileWriteBinary(faceB->edsk_filename,(char *)trackblock,256); - /* écriture des secteurs */ - idblock=t*9/2; - blockoffset=((t*9)%2)*512; - FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock][0]+blockoffset,512); - if (!blockoffset) { - FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+2][0]+512,512); /* C6 */ - FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+0][0]+512,512); /* C2 */ - FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+3][0]+0,512); /* C7 */ - FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+1][0]+0,512); /* C3 */ - FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+3][0]+512,512); /* C8 */ - FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+1][0]+512,512); /* C4 */ - FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+4][0]+0,512); /* C9 */ - FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+2][0]+0,512); /* C5 */ - } else { - FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+3][0]+0,512); /* C6 */ - FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+1][0]+0,512); /* C2 */ - FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+3][0]+512,512); /* C7 */ - FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+1][0]+512,512); /* C3 */ - FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+4][0]+0,512); /* C8 */ - FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+2][0]+0,512); /* C4 */ - FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+4][0]+512,512); /* C9 */ - FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+2][0]+512,512); /* C5 */ - } - } - } - FileWriteBinaryClose(faceA->edsk_filename); - rasm_printf(ae,KIO"Write edsk file %s\n",faceA->edsk_filename); -} -void EDSK_write(struct s_assenv *ae) -{ - #undef FUNC - #define FUNC "EDSK_write" - - struct s_edsk_wrapper *faceA,*faceB; - char *edskfilename; - int i,j; - - /* on passe en revue toutes les structs */ - for (i=0;inbedskwrapper;i++) { - /* already done */ - if (ae->edsk_wrapper[i].face==-1) continue; - - switch (ae->edsk_wrapper[i].face) { - default: - case 0:faceA=&ae->edsk_wrapper[i];faceB=NULL;break; - case 1:faceA=NULL;faceB=&ae->edsk_wrapper[i];break; - } - /* doit-on fusionner avec une autre face? */ - for (j=i+1;jnbedskwrapper;j++) { - if (!strcmp(ae->edsk_wrapper[i].edsk_filename,ae->edsk_wrapper[j].edsk_filename)) { - /* found another face for the floppy */ - switch (ae->edsk_wrapper[j].face) { - default: - case 0:faceA=&ae->edsk_wrapper[j];break; - case 1:faceB=&ae->edsk_wrapper[j];break; - } - } - } - EDSK_write_file(ae,faceA,faceB); - } -} -void PopAllSave(struct s_assenv *ae) -{ - #undef FUNC - #define FUNC "PopAllSave" - - unsigned char *AmsdosHeader; - char *dskfilename; - char *filename; - int offset,size,run; - int i,is,erreur=0,touched; - - for (is=0;isnbsave;is++) { - /* avoid quotes */ - filename=ae->wl[ae->save[is].iw].w; - filename[strlen(filename)-1]=0; - filename=TxtStrDup(filename+1); - /* translate tags! */ - filename=TranslateTag(ae,filename,&touched,1,E_TAGOPTION_REMOVESPACE); - -#if TRACE_EDSK - printf("woff=[%s](%d) wsize=[%s](%d)\n",ae->wl[ae->save[is].ioffset].w,ae->save[is].ioffset,ae->wl[ae->save[is].isize].w,ae->save[is].isize); -#endif - - ae->idx=ae->save[is].ioffset; /* exp hack */ - ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); - offset=RoundComputeExpression(ae,ae->wl[ae->idx].w,0,0,0); - - ae->idx=ae->save[is].isize; /* exp hack */ - ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); - size=RoundComputeExpression(ae,ae->wl[ae->idx].w,0,0,0); - - ae->idx=ae->save[is].irun; /* exp hack */ - if (ae->idx) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); - run=RoundComputeExpression(ae,ae->wl[ae->idx].w,0,0,0); - } else { - run=offset; - } - - if (size<1 || size>65536) { - MakeError(ae,NULL,0,"cannot save [%s] as the size is invalid!\n",filename); - continue; - } - if (offset<0 || offset>65535) { - MakeError(ae,NULL,0,"cannot save [%s] as the offset is invalid!\n",filename); - continue; - } - if (offset+size>65536) { - MakeError(ae,NULL,0,"cannot save [%s] as the offset+size will be out of bounds!\n",filename); - continue; - } - /* DSK management */ - if (ae->save[is].dsk) { - if (ae->save[is].iwdskname!=-1) { - /* obligé de dupliquer à cause du reuse */ - dskfilename=TxtStrDup(ae->wl[ae->save[is].iwdskname].w); - dskfilename[strlen(dskfilename)-1]=0; - if (!EDSK_addfile(ae,dskfilename+1,ae->save[is].face,filename,ae->mem[ae->save[is].ibank]+offset,size,offset,run)) { - erreur++; - break; - } - MemFree(dskfilename); - } - } else if (ae->save[is].tape) { - char TZX_header[10]; - unsigned char IDval[2]; - int wrksize,nbblock; - - /* output file on filesystem */ - FileRemoveIfExists(filename); - - strcpy(TZX_header,"ZXTape!"); - TZX_header[7]=0x1A; - TZX_header[8]=1; - TZX_header[9]=20; - FileWriteBinary(filename,(char *)TZX_header,10); - - IDval[0]=0x20; - FileWriteBinary(filename,(char *)IDval,1); - IDval[0]=0x03; - IDval[1]=0x03; - FileWriteBinary(filename,(char *)IDval,2); // first silence - - IDval[0]=0x10; - FileWriteBinary(filename,(char *)IDval,1); - IDval[0]=0x03; - IDval[1]=0x03; - FileWriteBinary(filename,(char *)IDval,2); // little silence - if (size+128<=2048) wrksize=size+128; else wrksize=2048; - IDval[0]=(wrksize+128) & 0xFF; - IDval[1]=((wrksize+128)>>8) & 0xFF; - FileWriteBinary(filename,(char *)IDval,2); // block len - nbblock=1; - AmsdosHeader=MakeAMSDOSHeader(run,offset,offset+size,MakeAMSDOS_name(ae,filename)); - FileWriteBinary(filename,(char *)AmsdosHeader,128); - if (size<=2048-128) { - FileWriteBinary(filename,(char*)ae->mem[ae->save[is].ibank]+offset,size); - } else { - FileWriteBinary(filename,(char*)ae->mem[ae->save[is].ibank]+offset,2048-128); - size=size-2048+128; - while (size>0) { - nbblock++; - /* additionnal block */ - IDval[0]=0x10; - FileWriteBinary(filename,(char *)IDval,1); - IDval[0]=0x04; - IDval[1]=0x04; - FileWriteBinary(filename,(char *)IDval,2); // silence 1s delay - if (size<=2048) wrksize=size; else wrksize=2048; - IDval[0]=(wrksize+128) & 0xFF; - IDval[1]=((wrksize+128)>>8) & 0xFF; - FileWriteBinary(filename,(char *)IDval,2); // block len - FileWriteBinary(filename,(char*)ae->mem[ae->save[is].ibank]+offset,wrksize); - /* adjust */ - size=size-2048; - } - } - FileWriteBinaryClose(filename); - rasm_printf(ae,KIO"Write tape file %s (%d block%s)\n",filename,nbblock,nbblock>1?"s":""); - } else { - /* output file on filesystem */ - rasm_printf(ae,KIO"Write binary file %s (%d byte%s)\n",filename,size,size>1?"s":""); - FileRemoveIfExists(filename); - if (ae->save[is].amsdos) { - AmsdosHeader=MakeAMSDOSHeader(run,offset,offset+size,MakeAMSDOS_name(ae,filename)); - FileWriteBinary(filename,(char *)AmsdosHeader,128); - } - FileWriteBinary(filename,(char*)ae->mem[ae->save[is].ibank]+offset,size); - FileWriteBinaryClose(filename); - } - MemFree(filename); - } - if (!erreur) EDSK_write(ae); - - for (i=0;inbedskwrapper;i++) { - MemFree(ae->edsk_wrapper[i].edsk_filename); - } - if (ae->maxedskwrapper) MemFree(ae->edsk_wrapper); - - if (ae->nbsave) { - MemFree(ae->save); - } -} - -void PopAllExpression(struct s_assenv *ae, int crunched_zone) -{ - #undef FUNC - #define FUNC "PopAllExpression" - - static int first=1; - double v; - long r; - int i; - unsigned char *mem; - char *expr; - - /* pop all expressions BUT thoses who where already computed (in crunched blocks) */ - - /* calcul des labels et expressions en zone crunch (et locale?) - les labels doivent pointer: - - une valeur absolue (numerique ou variable calculee) -> completement transparent - - un label dans la meme zone de crunch -> label->lz=1 && verif de la zone crunch - - un label hors zone crunch MAIS avant toute zone de crunch de la bank destination (!label->lz) - - idealement on doit tolerer les adresses situees apres le crunch dans une autre ORG zone! - - on utilise ae->stage pour créer un état intermédiaire dans le ComputeExpressionCore - */ - if (crunched_zone>=0) { - ae->stage=1; - } else { - /* on rescanne tout pour combler les trous */ - ae->stage=2; - first=1; - } - - for (i=first;iie;i++) { - /* first compute only crunched expression (0,1,2,3,...) then (-1) at the end */ - if (crunched_zone>=0) { - /* calcul des expressions en zone crunch */ - if (ae->expression[i].lzexpression[i].lz>crunched_zone) { - first=i; - break; - } - } else { - if (ae->expression[i].lz>=0) continue; - } - - mem=ae->mem[ae->expression[i].ibank]; - - if (ae->expression[i].reference) { - expr=ae->expression[i].reference; - } else { - expr=ae->wl[ae->expression[i].iw].w; - } - v=ComputeExpressionCore(ae,expr,ae->expression[i].ptr,i); - r=(long)floor(v+ae->rough); - switch (ae->expression[i].zetype) { - case E_EXPRESSION_J8: - r=r-ae->expression[i].ptr-2; - if (r<-128 || r>127) { - MakeError(ae,GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,"relative offset %d too far [%s]\n",r,ae->wl[ae->expression[i].iw].w); - } - mem[ae->expression[i].wptr]=(unsigned char)r; - break; - case E_EXPRESSION_IV81: - /* for enhanced 16bits instructions */ - r++; - case E_EXPRESSION_0V8: - case E_EXPRESSION_IV8: - case E_EXPRESSION_3V8: - case E_EXPRESSION_V8: - if (r>255 || r<-128) { - if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: truncating value #%X to #%X\n",GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,r,r&0xFF); - } - mem[ae->expression[i].wptr]=(unsigned char)r; - break; - case E_EXPRESSION_IV16: - case E_EXPRESSION_V16: - case E_EXPRESSION_V16C: - case E_EXPRESSION_0V16: - if (r>65535 || r<-32768) { - if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: truncating value #%X to #%X\n",GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,r,r&0xFFFF); - } - mem[ae->expression[i].wptr]=(unsigned char)r&0xFF; - mem[ae->expression[i].wptr+1]=(unsigned char)((r&0xFF00)>>8); - break; - case E_EXPRESSION_0V32: - /* meaningless in 32 bits architecture... */ - if (v>4294967295 || v<-2147483648) { - if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: truncating value\n",GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l); - } - mem[ae->expression[i].wptr]=(unsigned char)r&0xFF; - mem[ae->expression[i].wptr+1]=(unsigned char)((r>>8)&0xFF); - mem[ae->expression[i].wptr+2]=(unsigned char)((r>>16)&0xFF); - mem[ae->expression[i].wptr+3]=(unsigned char)((r>>24)&0xFF); - break; - case E_EXPRESSION_0VR: - /* convert v double value to Amstrad REAL */ - memcpy(&mem[ae->expression[i].wptr],__internal_MakeAmsdosREAL(ae,v,i),5); - break; - case E_EXPRESSION_IM: - switch (r) { - case 0x00:mem[ae->expression[i].wptr]=0x46;break; - case 0x01:mem[ae->expression[i].wptr]=0x56;break; - case 0x02:mem[ae->expression[i].wptr]=0x5E;break; - default: - MakeError(ae,GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,"IM 0,1 or 2 only\n"); - mem[ae->expression[i].wptr]=0; - } - break; - case E_EXPRESSION_RST: - switch (r) { - case 0x00:mem[ae->expression[i].wptr]=0xC7;break; - case 0x08:mem[ae->expression[i].wptr]=0xCF;break; - case 0x10:mem[ae->expression[i].wptr]=0xD7;break; - case 0x18:mem[ae->expression[i].wptr]=0xDF;break; - case 0x20:mem[ae->expression[i].wptr]=0xE7;break; - case 0x28:mem[ae->expression[i].wptr]=0xEF;break; - case 0x30:mem[ae->expression[i].wptr]=0xF7;break; - case 0x38:mem[ae->expression[i].wptr]=0xFF;break; - default: - MakeError(ae,GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,"RST #0,#8,#10,#18,#20,#28,#30,#38 only\n"); - mem[ae->expression[i].wptr]=0; - } - break; - case E_EXPRESSION_RUN: - if (r<0 || r>65535) { - if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: run adress truncated from %X to %X\n",GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,r,r&0xFFFF); - } - ae->snapshot.registers.LPC=r&0xFF; - ae->snapshot.registers.HPC=(r>>8)&0xFF; - break; - case E_EXPRESSION_ZXRUN: - if (r<0 || r>65535) { - if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: run adress truncated from %X to %X\n",GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,r,r&0xFFFF); - } - ae->zxsnapshot.run=r&0xFFFF; - break; - case E_EXPRESSION_ZXSTACK: - if (r<0 || r>65535) { - if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: stack adress truncated from %X to %X\n",GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,r,r&0xFFFF); - } - ae->zxsnapshot.stack=r&0xFFFF; - break; - case E_EXPRESSION_BRS: - if (r>=0 && r<8) { - mem[ae->expression[i].wptr]+=r*8; - } else { - MakeError(ae,GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,"SET,RES,BIT shift value from 0 to 7 only\n"); - } - break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"FATAL - unknown expression type\n",GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l); - FreeAssenv(ae);exit(-8); - } - } -} - -void InsertLabelToTree(struct s_assenv *ae, struct s_label *label) -{ - #undef FUNC - #define FUNC "InsertLabelToTree" - - struct s_crclabel_tree *curlabeltree; - int radix,dek=32; - - curlabeltree=&ae->labeltree; - while (dek) { - dek=dek-8; - radix=(label->crc>>dek)&0xFF; - if (curlabeltree->radix[radix]) { - curlabeltree=curlabeltree->radix[radix]; - } else { - curlabeltree->radix[radix]=MemMalloc(sizeof(struct s_crclabel_tree)); - curlabeltree=curlabeltree->radix[radix]; - memset(curlabeltree,0,sizeof(struct s_crclabel_tree)); - } - } - ObjectArrayAddDynamicValueConcat((void**)&curlabeltree->label,&curlabeltree->nlabel,&curlabeltree->mlabel,&label[0],sizeof(struct s_label)); -} - -/* use by structure mechanism and label import to add fake labels */ -void PushLabelLight(struct s_assenv *ae, struct s_label *curlabel) { - #undef FUNC - #define FUNC "PushLabelLight" - - struct s_label *searched_label; - - /* PushLabel light */ - if ((searched_label=SearchLabel(ae,curlabel->name,curlabel->crc))!=NULL) { - MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"%s caused duplicate label [%s]\n",ae->idx?"Structure insertion":"Label import",curlabel->name); - MemFree(curlabel->name); - } else { - curlabel->backidx=ae->il; - ObjectArrayAddDynamicValueConcat((void **)&ae->label,&ae->il,&ae->ml,curlabel,sizeof(struct s_label)); - InsertLabelToTree(ae,curlabel); - } -} -void PushLabel(struct s_assenv *ae) -{ - #undef FUNC - #define FUNC "PushLabel" - - struct s_label curlabel={0},*searched_label; - char *curlabelname; - int i; - /* label with counters */ - struct s_expr_dico *curdic; - char curval[32]; - char *varbuffer,*expr; - char *starttag,*endtag,*tagcheck; - int taglen,tagidx,lenw,tagcount=0; - int crc,newlen,touched; - - if (ae->AutomateValidLabelFirst[ae->wl[ae->idx].w[0]]) { - for (i=1;ae->wl[ae->idx].w[i];i++) { - if (ae->wl[ae->idx].w[i]=='{') tagcount++; else if (ae->wl[ae->idx].w[i]=='}') tagcount--; - if (!tagcount) { - if (!ae->AutomateValidLabel[ae->wl[ae->idx].w[i]]) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid char in label declaration (%c)\n",ae->wl[ae->idx].w[i]); - return; - } - } - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid first char in label declaration (%c)\n",ae->wl[ae->idx].w[0]); - return; - } - - switch (i) { - case 1: - switch (ae->wl[ae->idx].w[0]) { - case 'A': - case 'B': - case 'C': - case 'D': - case 'E': - case 'F': - case 'H': - case 'L': - case 'I': - case 'R': - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use reserved word [%s] for label\n",ae->wl[ae->idx].w); - return; - default:break; - } - break; - case 2: - if (strcmp(ae->wl[ae->idx].w,"AF")==0 || strcmp(ae->wl[ae->idx].w,"BC")==0 || strcmp(ae->wl[ae->idx].w,"DE")==0 || strcmp(ae->wl[ae->idx].w,"HL")==0 || - strcmp(ae->wl[ae->idx].w,"IX")==0 || strcmp(ae->wl[ae->idx].w,"IY")==0 || strcmp(ae->wl[ae->idx].w,"SP")==0 || - strcmp(ae->wl[ae->idx].w,"LX")==0 || strcmp(ae->wl[ae->idx].w,"HX")==0 || strcmp(ae->wl[ae->idx].w,"XL")==0 || strcmp(ae->wl[ae->idx].w,"XH")==0 || - strcmp(ae->wl[ae->idx].w,"LY")==0 || strcmp(ae->wl[ae->idx].w,"HY")==0 || strcmp(ae->wl[ae->idx].w,"YL")==0 || strcmp(ae->wl[ae->idx].w,"YH")==0) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use reserved word [%s] for label\n",ae->wl[ae->idx].w); - return; - } - break; - case 3: - if (strcmp(ae->wl[ae->idx].w,"IXL")==0 || strcmp(ae->wl[ae->idx].w,"IYL")==0 || strcmp(ae->wl[ae->idx].w,"IXH")==0 || strcmp(ae->wl[ae->idx].w,"IYH")==0) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use reserved word [%s] for label\n",ae->wl[ae->idx].w); - return; - } - break; - case 4: - if (strcmp(ae->wl[ae->idx].w,"VOID")==0) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use reserved word [%s] for label\n",ae->wl[ae->idx].w); - return; - } - default:break; - } - - /******************************************************* - v a r i a b l e s i n l a b e l n a m e - *******************************************************/ - varbuffer=TranslateTag(ae,TxtStrDup(ae->wl[ae->idx].w),&touched,1,E_TAGOPTION_NONE); - - /************************************************** - s t r u c t u r e d e c l a r a t i o n - **************************************************/ - if (ae->getstruct) { - struct s_rasmstructfield rasmstructfield={0}; - if (varbuffer[0]=='@') { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Please no local label in a struct [%s]\n",ae->wl[ae->idx].w); - return; - } - /* copy label+offset in the structure */ - rasmstructfield.name=TxtStrDup(varbuffer); - rasmstructfield.offset=ae->codeadr; - ObjectArrayAddDynamicValueConcat((void **)&ae->rasmstruct[ae->irasmstruct-1].rasmstructfield, - &ae->rasmstruct[ae->irasmstruct-1].irasmstructfield,&ae->rasmstruct[ae->irasmstruct-1].mrasmstructfield, - &rasmstructfield,sizeof(rasmstructfield)); - /* label is structname+field */ - curlabelname=curlabel.name=MemMalloc(strlen(ae->rasmstruct[ae->irasmstruct-1].name)+strlen(varbuffer)+2); - sprintf(curlabel.name,"%s.%s",ae->rasmstruct[ae->irasmstruct-1].name,varbuffer); - curlabel.iw=-1; - /* legacy */ - curlabel.crc=GetCRC(curlabel.name); - curlabel.ptr=ae->codeadr; -#if TRACE_STRUCT - printf("pushLabel (struct) [%X] [%s]\n",curlabel.ptr,curlabel.name); -#endif - } else { - /************************************************** - l a b e l s - **************************************************/ - /* labels locaux */ - if (varbuffer[0]=='@' && (ae->ir || ae->iw || ae->imacro)) { - curlabel.iw=-1; - curlabel.local=1; - curlabelname=curlabel.name=MakeLocalLabel(ae,varbuffer,NULL); - curlabel.crc=GetCRC(curlabel.name); - - /* local labels ALSO set new reference */ - if (ae->lastglobalalloc) { -//printf("push LOCAL is freeing lastgloballabel\n"); - MemFree(ae->lastgloballabel); - } - ae->lastgloballabel=TxtStrDup(curlabelname); -//printf("push LOCAL as reference for proximity label -> [%s]\n",ae->lastgloballabel); - ae->lastgloballabellen=strlen(ae->lastgloballabel); - ae->lastglobalalloc=1; - } else { - switch (varbuffer[0]) { - case '.': - if (ae->dams) { - /* old Dams style declaration (remove the dot) */ - i=0; - do { - varbuffer[i]=varbuffer[i+1]; - ae->wl[ae->idx].w[i]=ae->wl[ae->idx].w[i+1]; - i++; - } while (varbuffer[i]!=0); - if (!touched) { - curlabel.iw=ae->idx; - } else { - curlabel.iw=-1; - curlabel.name=varbuffer; - } - curlabel.crc=GetCRC(varbuffer); - curlabelname=varbuffer; - } else { - /* proximity labels */ - if (ae->lastgloballabel) { - curlabelname=MemMalloc(strlen(varbuffer)+1+ae->lastgloballabellen); - sprintf(curlabelname,"%s%s",ae->lastgloballabel,varbuffer); - MemFree(varbuffer); - touched=1; // cause realloc! - curlabel.iw=-1; - curlabel.name=varbuffer=curlabelname; - curlabel.crc=GetCRC(varbuffer); -//printf("push proximity label that may be exported [%s]->[%s]\n",ae->wl[ae->idx].w,varbuffer); - } else { - /* MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"cannot create proximity label [%s] as there is no previous global label\n",varbuffer); - return; */ - - // not optimal but! - curlabelname=TxtStrDup(varbuffer); - MemFree(varbuffer); - touched=1; // cause realloc! - curlabel.iw=-1; - curlabel.name=varbuffer=curlabelname; - curlabel.crc=GetCRC(varbuffer); - } - } - break; - default: - if (!touched) { - curlabel.iw=ae->idx; - } else { - curlabel.iw=-1; - curlabel.name=varbuffer; - } - curlabel.crc=GetCRC(varbuffer); - curlabelname=varbuffer; - /* global labels set new reference */ - if (ae->lastglobalalloc) MemFree(ae->lastgloballabel); - ae->lastgloballabel=ae->wl[ae->idx].w; - ae->lastsuperglobal=ae->wl[ae->idx].w; - ae->lastgloballabellen=strlen(ae->wl[ae->idx].w); - ae->lastglobalalloc=0; -//printf("SET global label [%s] l=%d\n",ae->lastgloballabel,ae->lastgloballabellen); - break; - } - - /* contrôle dico uniquement avec des labels non locaux */ - if (SearchDico(ae,curlabelname,curlabel.crc)) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"cannot create label [%s] as there is already a variable with the same name\n",curlabelname); - return; - } - if(SearchAlias(ae,curlabel.crc,curlabelname)!=-1) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"cannot create label [%s] as there is already an alias with the same name\n",curlabelname); - return; - } - } - curlabel.ptr=ae->codeadr; - curlabel.ibank=ae->activebank; - curlabel.iorgzone=ae->io-1; - curlabel.lz=ae->lz; - } - - if ((searched_label=SearchLabel(ae,curlabelname,curlabel.crc))!=NULL) { - MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"Duplicate label [%s] - previously defined in [%s:%d]\n",curlabelname,ae->filename[searched_label->fileidx],searched_label->fileline); - if (curlabel.iw==-1) MemFree(curlabelname); - } else { -//printf("PushLabel(%s) name=%s crc=%X\n",curlabelname,curlabel.name?curlabel.name:"null",curlabel.crc); - curlabel.fileidx=ae->wl[ae->idx].ifile; - curlabel.fileline=ae->wl[ae->idx].l; - curlabel.autorise_export=ae->autorise_export; - curlabel.backidx=ae->il; - ObjectArrayAddDynamicValueConcat((void **)&ae->label,&ae->il,&ae->ml,&curlabel,sizeof(curlabel)); - InsertLabelToTree(ae,&curlabel); - } - - if (!touched) MemFree(varbuffer); -} - - -unsigned char *EncodeSnapshotRLE(unsigned char *memin, int *lenout) { - #undef FUNC - #define FUNC "EncodeSnapshotRLE" - - int i,cpt,idx=0; - unsigned char *memout=NULL; - - memout=MemMalloc(65540); - - for (i=0;i<65536;) { - for (cpt=1;cpt<255;cpt++) if (memin[i]!=memin[i+cpt]) break; - if (cpt>=3 || memin[i]==0xE5) { - memout[idx++]=0xE5; - memout[idx++]=cpt; - memout[idx++]=memin[i]; - i+=cpt; - } else { - memout[idx++]=memin[i++]; - } - } - if (lenout) *lenout=idx; - if (idx<65536) return memout; - - MemFree(memout); - return NULL; -} - - - -#undef FUNC -#define FUNC "Instruction CORE" - -void _IN(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { - if (strcmp(ae->wl[ae->idx+2].w,"(C)")==0) { - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_0: - case CRC_F:___output(ae,0xED);___output(ae,0x70);ae->nop+=4;break; - case CRC_A:___output(ae,0xED);___output(ae,0x78);ae->nop+=3;break; - case CRC_B:___output(ae,0xED);___output(ae,0x40);ae->nop+=4;break; - case CRC_C:___output(ae,0xED);___output(ae,0x48);ae->nop+=4;break; - case CRC_D:___output(ae,0xED);___output(ae,0x50);ae->nop+=4;break; - case CRC_E:___output(ae,0xED);___output(ae,0x58);ae->nop+=4;break; - case CRC_H:___output(ae,0xED);___output(ae,0x60);ae->nop+=4;break; - case CRC_L:___output(ae,0xED);___output(ae,0x68);ae->nop+=4;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is IN [0,F,A,B,C,D,E,H,L],(C)\n"); - } - } else if (strcmp(ae->wl[ae->idx+1].w,"A")==0 && StringIsMem(ae->wl[ae->idx+2].w)) { - ___output(ae,0xDB); - PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); - ae->nop+=3; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IN [0,F,A,B,C,D,E,H,L],(C) or IN A,(n) only\n"); - } - ae->idx+=2; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IN [0,F,A,B,C,D,E,H,L],(C) or IN A,(n) only\n"); - } -} - -void _OUT(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { - if (strcmp(ae->wl[ae->idx+1].w,"(C)")==0) { - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_0:___output(ae,0xED);___output(ae,0x71);ae->nop+=4;break; - case CRC_A:___output(ae,0xED);___output(ae,0x79);ae->nop+=4;break; - case CRC_B:___output(ae,0xED);___output(ae,0x41);ae->nop+=4;break; - case CRC_C:___output(ae,0xED);___output(ae,0x49);ae->nop+=4;break; - case CRC_D:___output(ae,0xED);___output(ae,0x51);ae->nop+=4;break; - case CRC_E:___output(ae,0xED);___output(ae,0x59);ae->nop+=4;break; - case CRC_H:___output(ae,0xED);___output(ae,0x61);ae->nop+=4;break; - case CRC_L:___output(ae,0xED);___output(ae,0x69);ae->nop+=4;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is OUT (C),[0,A,B,C,D,E,H,L]\n"); - } - } else if (strcmp(ae->wl[ae->idx+2].w,"A")==0 && StringIsMem(ae->wl[ae->idx+1].w)) { - ___output(ae,0xD3); - PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); - ae->nop+=3; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"OUT (C),[0,A,B,C,D,E,H,L] or OUT (n),A only\n"); - } - ae->idx+=2; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"OUT (C),[0,A,B,C,D,E,H,L] or OUT (n),A only\n"); - } -} - -void _EX(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_HL: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_DE:___output(ae,0xEB);ae->nop+=1;break; - case CRC_MSP:___output(ae,0xE3);ae->nop+=6;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is EX HL,[(SP),DE]\n"); - } - break; - case CRC_AF: - if (strcmp(ae->wl[ae->idx+2].w,"AF'")==0) { - ___output(ae,0x08);ae->nop+=1; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is EX AF,AF'\n"); - } - break; - case CRC_MSP: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_HL:___output(ae,0xE3);ae->nop+=6;break; - case CRC_IX:___output(ae,0xDD);___output(ae,0xE3);ae->nop+=7;break; - case CRC_IY:___output(ae,0xFD);___output(ae,0xE3);ae->nop+=7;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is EX (SP),[HL,IX,IY]\n"); - } - break; - case CRC_DE: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_HL:___output(ae,0xEB);ae->nop+=1;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is EX DE,HL\n"); - } - break; - case CRC_IX: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_MSP:___output(ae,0xDD);___output(ae,0xE3);ae->nop+=7;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is EX IX,(SP)\n"); - } - break; - case CRC_IY: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_MSP:___output(ae,0xFD);___output(ae,0xE3);ae->nop+=7;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is EX IY,(SP)\n"); - } - break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is EX [AF,DE,HL,(SP),IX,IY],reg16\n"); - } - ae->idx+=2; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use EX reg16,reg16\n"); - } -} - -void _SBC(struct s_assenv *ae) { - if ((!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) || ((!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) && strcmp(ae->wl[ae->idx+1].w,"A")==0)) { - if (!ae->wl[ae->idx+1].t) ae->idx++; - /* do implicit A */ - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_A:___output(ae,0x9F);ae->nop+=1;break; - case CRC_MHL:___output(ae,0x9E);ae->nop+=2;break; - case CRC_B:___output(ae,0x98);ae->nop+=1;break; - case CRC_C:___output(ae,0x99);ae->nop+=1;break; - case CRC_D:___output(ae,0x9A);ae->nop+=1;break; - case CRC_E:___output(ae,0x9B);ae->nop+=1;break; - case CRC_H:___output(ae,0x9C);ae->nop+=1;break; - case CRC_L:___output(ae,0x9D);ae->nop+=1;break; - case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x9C);ae->nop+=2;break; - case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x9D);ae->nop+=2;break; - case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x9C);ae->nop+=2;break; - case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x9D);ae->nop+=2;break; - case CRC_IX:case CRC_IY: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use SBC with A,B,C,D,E,H,L,XH,XL,YH,YL,(HL),(IX),(IY)\n"); - ae->idx++; - return; - default: - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,0x9E); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ae->nop+=3; - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,0x9E); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ae->nop+=3; - } else { - ___output(ae,0xDE); - PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); - ae->nop+=2; - } - } - ae->idx++; - } else if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_HL: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_BC:___output(ae,0xED);___output(ae,0x42);ae->nop+=4;break; - case CRC_DE:___output(ae,0xED);___output(ae,0x52);ae->nop+=4;break; - case CRC_HL:___output(ae,0xED);___output(ae,0x62);ae->nop+=4;break; - case CRC_SP:___output(ae,0xED);___output(ae,0x72);ae->nop+=4;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SBC HL,[BC,DE,HL,SP]\n"); - } - break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SBC HL,[BC,DE,HL,SP]\n"); - } - ae->idx+=2; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid syntax for SBC\n"); - } -} - -void _ADC(struct s_assenv *ae) { - if ((!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) || ((!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) && strcmp(ae->wl[ae->idx+1].w,"A")==0)) { - if (!ae->wl[ae->idx+1].t) ae->idx++; - /* also implicit A */ - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_A:___output(ae,0x8F);ae->nop+=1;break; - case CRC_MHL:___output(ae,0x8E);ae->nop+=2;break; - case CRC_B:___output(ae,0x88);ae->nop+=1;break; - case CRC_C:___output(ae,0x89);ae->nop+=1;break; - case CRC_D:___output(ae,0x8A);ae->nop+=1;break; - case CRC_E:___output(ae,0x8B);ae->nop+=1;break; - case CRC_H:___output(ae,0x8C);ae->nop+=1;break; - case CRC_L:___output(ae,0x8D);ae->nop+=1;break; - case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x8C);ae->nop+=2;break; - case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x8D);ae->nop+=2;break; - case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x8C);ae->nop+=2;break; - case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x8D);ae->nop+=2;break; - case CRC_IX:case CRC_IY: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use ADC with A,B,C,D,E,H,L,XH,XL,YH,YL,(HL),(IX),(IY)\n"); - ae->idx++; - return; - default: - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,0x8E); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ae->nop+=3; - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,0x8E); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ae->nop+=3; - } else { - ___output(ae,0xCE); - PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); - ae->nop+=2; - } - } - ae->idx++; - } else if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_HL: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_BC:___output(ae,0xED);___output(ae,0x4A);ae->nop+=4;break; - case CRC_DE:___output(ae,0xED);___output(ae,0x5A);ae->nop+=4;break; - case CRC_HL:___output(ae,0xED);___output(ae,0x6A);ae->nop+=4;break; - case CRC_SP:___output(ae,0xED);___output(ae,0x7A);ae->nop+=4;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is ADC HL,[BC,DE,HL,SP]\n"); - } - break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is ADC HL,[BC,DE,HL,SP]\n"); - } - ae->idx+=2; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid syntax for ADC\n"); - } -} - -void _ADD(struct s_assenv *ae) { - if ((!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) || ((!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) && strcmp(ae->wl[ae->idx+1].w,"A")==0)) { - if (!ae->wl[ae->idx+1].t) ae->idx++; - /* also implicit A */ - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_A:___output(ae,0x87);ae->nop+=1;break; - case CRC_MHL:___output(ae,0x86);ae->nop+=2;break; - case CRC_B:___output(ae,0x80);ae->nop+=1;break; - case CRC_C:___output(ae,0x81);ae->nop+=1;break; - case CRC_D:___output(ae,0x82);ae->nop+=1;break; - case CRC_E:___output(ae,0x83);ae->nop+=1;break; - case CRC_H:___output(ae,0x84);ae->nop+=1;break; - case CRC_L:___output(ae,0x85);ae->nop+=1;break; - case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x84);ae->nop+=2;break; - case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x85);ae->nop+=2;break; - case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x84);ae->nop+=2;break; - case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x85);ae->nop+=2;break; - case CRC_IX:case CRC_IY: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use ADD with A,B,C,D,E,H,L,XH,XL,YH,YL,(HL),(IX),(IY)\n"); - ae->idx++; - return; - default: - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,0x86); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ae->nop+=5; - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,0x86); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ae->nop+=5; - } else { - ___output(ae,0xC6); - PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); - ae->nop+=2; - } - } - ae->idx++; - } else if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_HL: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_BC:___output(ae,0x09);ae->nop+=3;break; - case CRC_DE:___output(ae,0x19);ae->nop+=3;break; - case CRC_HL:___output(ae,0x29);ae->nop+=3;break; - case CRC_SP:___output(ae,0x39);ae->nop+=3;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is ADD HL,[BC,DE,HL,SP]\n"); - } - break; - case CRC_IX: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_BC:___output(ae,0xDD);___output(ae,0x09);ae->nop+=4;break; - case CRC_DE:___output(ae,0xDD);___output(ae,0x19);ae->nop+=4;break; - case CRC_IX:___output(ae,0xDD);___output(ae,0x29);ae->nop+=4;break; - case CRC_SP:___output(ae,0xDD);___output(ae,0x39);ae->nop+=4;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is ADD IX,[BC,DE,IX,SP]\n"); - } - break; - case CRC_IY: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_BC:___output(ae,0xFD);___output(ae,0x09);ae->nop+=4;break; - case CRC_DE:___output(ae,0xFD);___output(ae,0x19);ae->nop+=4;break; - case CRC_IY:___output(ae,0xFD);___output(ae,0x29);ae->nop+=4;break; - case CRC_SP:___output(ae,0xFD);___output(ae,0x39);ae->nop+=4;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is ADD IY,[BC,DE,IY,SP]\n"); - } - break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is ADD [HL,IX,IY],reg16\n"); - } - ae->idx+=2; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid syntax for ADD\n"); - } -} - -void _CP(struct s_assenv *ae) { - if ((!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) || ((!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) && strcmp(ae->wl[ae->idx+1].w,"A")==0)) { - if (!ae->wl[ae->idx+1].t) ae->idx++; - /* also implicit A */ - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_A:___output(ae,0xBF);ae->nop+=1;break; - case CRC_MHL:___output(ae,0xBE);ae->nop+=2;break; - case CRC_B:___output(ae,0xB8);ae->nop+=1;break; - case CRC_C:___output(ae,0xB9);ae->nop+=1;break; - case CRC_D:___output(ae,0xBA);ae->nop+=1;break; - case CRC_E:___output(ae,0xBB);ae->nop+=1;break; - case CRC_H:___output(ae,0xBC);ae->nop+=1;break; - case CRC_L:___output(ae,0xBD);ae->nop+=1;break; - case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0xBC);ae->nop+=2;break; - case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0xBD);ae->nop+=2;break; - case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0xBC);ae->nop+=2;break; - case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0xBD);ae->nop+=2;break; - default: - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,0xBE); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ae->nop+=5; - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,0xBE); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ae->nop+=5; - } else { - ___output(ae,0xFE); - PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); - ae->nop+=2; - } - } - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Syntax is CP reg8/(reg16)\n"); - } -} - -void _RET(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_NZ:___output(ae,0xC0);ae->nop+=2;break; - case CRC_Z:___output(ae,0xC8);ae->nop+=2;break; - case CRC_C:___output(ae,0xD8);ae->nop+=2;break; - case CRC_NC:___output(ae,0xD0);ae->nop+=2;break; - case CRC_PE:___output(ae,0xE8);ae->nop+=2;break; - case CRC_PO:___output(ae,0xE0);ae->nop+=2;break; - case CRC_P:___output(ae,0xF0);ae->nop+=2;break; - case CRC_M:___output(ae,0xF8);ae->nop+=2;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Available flags for RET are C,NC,Z,NZ,PE,PO,P,M\n"); - } - ae->idx++; - } else if (ae->wl[ae->idx].t==1) { - ___output(ae,0xC9); - ae->nop+=3; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid RET syntax\n"); - } -} - -void _CALL(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==0 && ae->wl[ae->idx+2].t==1) { - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_C:___output(ae,0xDC);ae->nop+=3;break; - case CRC_Z:___output(ae,0xCC);ae->nop+=3;break; - case CRC_NZ:___output(ae,0xC4);ae->nop+=3;break; - case CRC_NC:___output(ae,0xD4);ae->nop+=3;break; - case CRC_PE:___output(ae,0xEC);ae->nop+=3;break; - case CRC_PO:___output(ae,0xE4);ae->nop+=3;break; - case CRC_P:___output(ae,0xF4);ae->nop+=3;break; - case CRC_M:___output(ae,0xFC);ae->nop+=3;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Available flags for CALL are C,NC,Z,NZ,PE,PO,P,M\n"); - } - PushExpression(ae,ae->idx+2,E_EXPRESSION_V16C); - ae->idx+=2; - } else if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - ___output(ae,0xCD); - PushExpression(ae,ae->idx+1,E_EXPRESSION_V16C); - ae->idx++; - ae->nop+=5; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid CALL syntax\n"); - } -} - -void _JR(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==0 && ae->wl[ae->idx+2].t==1) { - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_NZ:___output(ae,0x20);ae->nop+=2;break; - case CRC_C:___output(ae,0x38);ae->nop+=2;break; - case CRC_Z:___output(ae,0x28);ae->nop+=2;break; - case CRC_NC:___output(ae,0x30);ae->nop+=2;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Available flags for JR are C,NC,Z,NZ\n"); - } - PushExpression(ae,ae->idx+2,E_EXPRESSION_J8); - ae->idx+=2; - } else if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - ___output(ae,0x18); - PushExpression(ae,ae->idx+1,E_EXPRESSION_J8); - ae->idx++; - ae->nop+=3; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid JR syntax\n"); - } -} - -void _JP(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==0 && ae->wl[ae->idx+2].t==1) { - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_C:___output(ae,0xDA);ae->nop+=3;break; - case CRC_Z:___output(ae,0xCA);ae->nop+=3;break; - case CRC_NZ:___output(ae,0xC2);ae->nop+=3;break; - case CRC_NC:___output(ae,0xD2);ae->nop+=3;break; - case CRC_PE:___output(ae,0xEA);ae->nop+=3;break; - case CRC_PO:___output(ae,0xE2);ae->nop+=3;break; - case CRC_P:___output(ae,0xF2);ae->nop+=3;break; - case CRC_M:___output(ae,0xFA);ae->nop+=3;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Available flags for JP are C,NC,Z,NZ,PE,PO,P,M\n"); - } - if (!strcmp(ae->wl[ae->idx+2].w,"(IX)") || !strcmp(ae->wl[ae->idx+2].w,"(IY)")) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"conditionnal JP cannot use register adressing\n"); - } else { - PushExpression(ae,ae->idx+2,E_EXPRESSION_V16); - } - ae->idx+=2; - } else if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_HL:case CRC_MHL:___output(ae,0xE9);ae->nop+=1;break; - case CRC_IX:case CRC_MIX:___output(ae,0xDD);___output(ae,0xE9);ae->nop+=2;break; - case CRC_IY:case CRC_MIY:___output(ae,0xFD);___output(ae,0xE9);ae->nop+=2;break; - default: - ___output(ae,0xC3); - PushExpression(ae,ae->idx+1,E_EXPRESSION_V16); - } - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid JP syntax\n"); - } -} - - -void _DEC(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t) { - do { - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_A:___output(ae,0x3D);ae->nop+=1;break; - case CRC_B:___output(ae,0x05);ae->nop+=1;break; - case CRC_C:___output(ae,0x0D);ae->nop+=1;break; - case CRC_D:___output(ae,0x15);ae->nop+=1;break; - case CRC_E:___output(ae,0x1D);ae->nop+=1;break; - case CRC_H:___output(ae,0x25);ae->nop+=1;break; - case CRC_L:___output(ae,0x2D);ae->nop+=1;break; - case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x25);ae->nop+=2;break; - case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x2D);ae->nop+=2;break; - case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x25);ae->nop+=2;break; - case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x2D);ae->nop+=2;break; - case CRC_BC:___output(ae,0x0B);ae->nop+=2;break; - case CRC_DE:___output(ae,0x1B);ae->nop+=2;break; - case CRC_HL:___output(ae,0x2B);ae->nop+=2;break; - case CRC_IX:___output(ae,0xDD);___output(ae,0x2B);ae->nop+=3;break; - case CRC_IY:___output(ae,0xFD);___output(ae,0x2B);ae->nop+=3;break; - case CRC_SP:___output(ae,0x3B);ae->nop+=2;break; - case CRC_MHL:___output(ae,0x35);ae->nop+=3;break; - default: - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,0x35); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ae->nop+=6; - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,0x35); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ae->nop+=6; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use DEC with A,B,C,D,E,H,L,XH,XL,YH,YL,BC,DE,HL,SP,(HL),(IX),(IY)\n"); - } - } - ae->idx++; - } while (ae->wl[ae->idx].t==0); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use DEC with A,B,C,D,E,H,L,XH,XL,YH,YL,BC,DE,HL,SP,(HL),(IX),(IY)\n"); - } -} -void _INC(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t) { - do { - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_A:___output(ae,0x3C);ae->nop+=1;break; - case CRC_B:___output(ae,0x04);ae->nop+=1;break; - case CRC_C:___output(ae,0x0C);ae->nop+=1;break; - case CRC_D:___output(ae,0x14);ae->nop+=1;break; - case CRC_E:___output(ae,0x1C);ae->nop+=1;break; - case CRC_H:___output(ae,0x24);ae->nop+=1;break; - case CRC_L:___output(ae,0x2C);ae->nop+=1;break; - case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x24);ae->nop+=2;break; - case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x2C);ae->nop+=2;break; - case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x24);ae->nop+=2;break; - case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x2C);ae->nop+=2;break; - case CRC_BC:___output(ae,0x03);ae->nop+=2;break; - case CRC_DE:___output(ae,0x13);ae->nop+=2;break; - case CRC_HL:___output(ae,0x23);ae->nop+=2;break; - case CRC_IX:___output(ae,0xDD);___output(ae,0x23);ae->nop+=3;break; - case CRC_IY:___output(ae,0xFD);___output(ae,0x23);ae->nop+=3;break; - case CRC_SP:___output(ae,0x33);ae->nop+=2;break; - case CRC_MHL:___output(ae,0x34);ae->nop+=3;break; - default: - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,0x34); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ae->nop+=6; - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,0x34); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ae->nop+=6; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use INC with A,B,C,D,E,H,L,XH,XL,YH,YL,BC,DE,HL,SP,(HL),(IX),(IY)\n"); - } - } - ae->idx++; - } while (ae->wl[ae->idx].t==0); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use INC with A,B,C,D,E,H,L,XH,XL,YH,YL,BC,DE,HL,SP,(HL),(IX),(IY)\n"); - } -} - -void _SUB(struct s_assenv *ae) { - #ifdef OPCODE - #undef OPCODE - #endif - #define OPCODE 0x90 - - if ((!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) || ((!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) && strcmp(ae->wl[ae->idx+1].w,"A")==0)) { - if (!ae->wl[ae->idx+1].t) ae->idx++; - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_A:___output(ae,OPCODE+7);ae->nop+=1;break; - case CRC_MHL:___output(ae,OPCODE+6);ae->nop+=2;break; - case CRC_B:___output(ae,OPCODE);ae->nop+=1;break; - case CRC_C:___output(ae,OPCODE+1);ae->nop+=1;break; - case CRC_D:___output(ae,OPCODE+2);ae->nop+=1;break; - case CRC_E:___output(ae,OPCODE+3);ae->nop+=1;break; - case CRC_H:___output(ae,OPCODE+4);ae->nop+=1;break; - case CRC_L:___output(ae,OPCODE+5);ae->nop+=1;break; - case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,OPCODE+4);ae->nop+=2;break; - case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,OPCODE+5);ae->nop+=2;break; - case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,OPCODE+4);ae->nop+=2;break; - case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,OPCODE+5);ae->nop+=2;break; - case CRC_IX:case CRC_IY: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use SUB with A,B,C,D,E,H,L,XH,XL,YH,YL,(HL),(IX),(IY)\n"); - ae->idx++; - return; - default: - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,OPCODE+6); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ae->nop+=5; - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,OPCODE+6); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ae->nop+=5; - } else { - ___output(ae,0xD6); - PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); - ae->nop+=2; - } - } - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use SUB with A,B,C,D,E,H,L,XH,XL,YH,YL,(HL),(IX),(IY)\n"); - } -} -void _AND(struct s_assenv *ae) { - #ifdef OPCODE - #undef OPCODE - #endif - #define OPCODE 0xA0 - - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_A:___output(ae,OPCODE+7);ae->nop+=1;break; - case CRC_MHL:___output(ae,OPCODE+6);ae->nop+=2;break; - case CRC_B:___output(ae,OPCODE);ae->nop+=1;break; - case CRC_C:___output(ae,OPCODE+1);ae->nop+=1;break; - case CRC_D:___output(ae,OPCODE+2);ae->nop+=1;break; - case CRC_E:___output(ae,OPCODE+3);ae->nop+=1;break; - case CRC_H:___output(ae,OPCODE+4);ae->nop+=1;break; - case CRC_L:___output(ae,OPCODE+5);ae->nop+=1;break; - case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,OPCODE+4);ae->nop+=2;break; - case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,OPCODE+5);ae->nop+=2;break; - case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,OPCODE+4);ae->nop+=2;break; - case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,OPCODE+5);ae->nop+=2;break; - default: - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,OPCODE+6); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ae->nop+=5; - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,OPCODE+6); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ae->nop+=5; - } else { - ___output(ae,0xE6); - PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); - ae->nop+=2; - } - } - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use AND with A,B,C,D,E,H,L,XH,XL,YH,YL,(HL),(IX),(IY)\n"); - } -} -void _OR(struct s_assenv *ae) { - #ifdef OPCODE - #undef OPCODE - #endif - #define OPCODE 0xB0 - - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_A:___output(ae,OPCODE+7);ae->nop+=1;break; - case CRC_MHL:___output(ae,OPCODE+6);ae->nop+=2;break; - case CRC_B:___output(ae,OPCODE);ae->nop+=1;break; - case CRC_C:___output(ae,OPCODE+1);ae->nop+=1;break; - case CRC_D:___output(ae,OPCODE+2);ae->nop+=1;break; - case CRC_E:___output(ae,OPCODE+3);ae->nop+=1;break; - case CRC_H:___output(ae,OPCODE+4);ae->nop+=1;break; - case CRC_L:___output(ae,OPCODE+5);ae->nop+=1;break; - case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,OPCODE+4);ae->nop+=2;break; - case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,OPCODE+5);ae->nop+=2;break; - case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,OPCODE+4);ae->nop+=2;break; - case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,OPCODE+5);ae->nop+=2;break; - default: - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,OPCODE+6); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ae->nop+=5; - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,OPCODE+6); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ae->nop+=5; - } else { - ___output(ae,0xF6); - PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); - ae->nop+=2; - } - } - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use OR with A,B,C,D,E,H,L,XH,XL,YH,YL,(HL),(IX),(IY)\n"); - } -} -void _XOR(struct s_assenv *ae) { - #ifdef OPCODE - #undef OPCODE - #endif - #define OPCODE 0xA8 - - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_A:___output(ae,OPCODE+7);ae->nop+=1;break; - case CRC_MHL:___output(ae,OPCODE+6);ae->nop+=2;break; - case CRC_B:___output(ae,OPCODE);ae->nop+=1;break; - case CRC_C:___output(ae,OPCODE+1);ae->nop+=1;break; - case CRC_D:___output(ae,OPCODE+2);ae->nop+=1;break; - case CRC_E:___output(ae,OPCODE+3);ae->nop+=1;break; - case CRC_H:___output(ae,OPCODE+4);ae->nop+=1;break; - case CRC_L:___output(ae,OPCODE+5);ae->nop+=1;break; - case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,OPCODE+4);ae->nop+=2;break; - case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,OPCODE+5);ae->nop+=2;break; - case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,OPCODE+4);ae->nop+=2;break; - case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,OPCODE+5);ae->nop+=2;break; - default: - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,OPCODE+6); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ae->nop+=5; - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,OPCODE+6); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ae->nop+=5; - } else { - ___output(ae,0xEE); - PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); - ae->nop+=2; - } - } - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use XOR with A,B,C,D,E,H,L,XH,XL,YH,YL,(HL),(IX),(IY)\n"); - } -} - - -void _POP(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t) { - do { - ae->idx++; - switch (GetCRC(ae->wl[ae->idx].w)) { - case CRC_AF:___output(ae,0xF1);ae->nop+=3;break; - case CRC_BC:___output(ae,0xC1);ae->nop+=3;break; - case CRC_DE:___output(ae,0xD1);ae->nop+=3;break; - case CRC_HL:___output(ae,0xE1);ae->nop+=3;break; - case CRC_IX:___output(ae,0xDD);___output(ae,0xE1);ae->nop+=4;break; - case CRC_IY:___output(ae,0xFD);___output(ae,0xE1);ae->nop+=4;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use POP with AF,BC,DE,HL,IX,IY\n"); - } - } while (ae->wl[ae->idx].t!=1); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"POP need at least one parameter\n"); - } -} -void _PUSH(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t) { - do { - ae->idx++; - switch (GetCRC(ae->wl[ae->idx].w)) { - case CRC_AF:___output(ae,0xF5);ae->nop+=4;break; - case CRC_BC:___output(ae,0xC5);ae->nop+=4;break; - case CRC_DE:___output(ae,0xD5);ae->nop+=4;break; - case CRC_HL:___output(ae,0xE5);ae->nop+=4;break; - case CRC_IX:___output(ae,0xDD);___output(ae,0xE5);ae->nop+=5;break; - case CRC_IY:___output(ae,0xFD);___output(ae,0xE5);ae->nop+=5;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use PUSH with AF,BC,DE,HL,IX,IY\n"); - } - } while (ae->wl[ae->idx].t!=1); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"PUSH need at least one parameter\n"); - } -} - -void _IM(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - /* la valeur du parametre va definir l'opcode du IM */ - ___output(ae,0xED); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IM); - ae->idx++; - ae->nop+=2; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IM need one parameter\n"); - } -} - -void _RLCA(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0x7); - ae->nop+=1; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RLCA does not need parameter\n"); - } -} -void _RRCA(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0xF); - ae->nop+=1; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RRCA does not need parameter\n"); - } -} -void _NEG(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0xED); - ___output(ae,0x44); - ae->nop+=2; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"NEG does not need parameter\n"); - } -} -void _DAA(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0x27); - ae->nop+=1; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DAA does not need parameter\n"); - } -} -void _CPL(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0x2F); - ae->nop+=1; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CPL does not need parameter\n"); - } -} -void _RETI(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0xED); - ___output(ae,0x4D); - ae->nop+=4; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RETI does not need parameter\n"); - } -} -void _SCF(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0x37); - ae->nop+=1; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SCF does not need parameter\n"); - } -} -void _LDD(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0xED); - ___output(ae,0xA8); - ae->nop+=5; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LDD does not need parameter\n"); - } -} -void _LDDR(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0xED); - ___output(ae,0xB8); - ae->nop+=5; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LDDR does not need parameter\n"); - } -} -void _LDI(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0xED); - ___output(ae,0xA0); - ae->nop+=5; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LDI does not need parameter\n"); - } -} -void _LDIR(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0xED); - ___output(ae,0xB0); - ae->nop+=5; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LDIR does not need parameter\n"); - } -} -void _CCF(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0x3F); - ae->nop+=5; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CCF does not need parameter\n"); - } -} -void _CPD(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0xED); - ___output(ae,0xA9); - ae->nop+=4; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CPD does not need parameter\n"); - } -} -void _CPDR(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0xED); - ___output(ae,0xB9); - ae->nop+=4; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CPDR does not need parameter\n"); - } -} -void _CPI(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0xED); - ___output(ae,0xA1); - ae->nop+=4; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CPI does not need parameter\n"); - } -} -void _CPIR(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0xED); - ___output(ae,0xB1); - ae->nop+=4; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CPIR does not need parameter\n"); - } -} -void _OUTD(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0xED); - ___output(ae,0xAB); - ae->nop+=5; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"OUTD does not need parameter\n"); - } -} -void _OTDR(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0xED); - ___output(ae,0xBB); - ae->nop+=5; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"OTDR does not need parameter\n"); - } -} -void _OUTI(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0xED); - ___output(ae,0xA3); - ae->nop+=5; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"OUTI does not need parameter\n"); - } -} -void _OTIR(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0xED); - ___output(ae,0xB3); - ae->nop+=5; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"OTIR does not need parameter\n"); - } -} -void _RETN(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0xED); - ___output(ae,0x45); - ae->nop+=4; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RETN does not need parameter\n"); - } -} -void _IND(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0xED); - ___output(ae,0xAA); - ae->nop+=5; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IND does not need parameter\n"); - } -} -void _INDR(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0xED); - ___output(ae,0xBA); - ae->nop+=5; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INDR does not need parameter\n"); - } -} -void _INI(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0xED); - ___output(ae,0xA2); - ae->nop+=5; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INI does not need parameter\n"); - } -} -void _INIR(struct s_assenv *ae) { - if (ae->wl[ae->idx].t==1) { - ___output(ae,0xED); - ___output(ae,0xB2); - ae->nop+=5; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INIR does not need parameter\n"); - } -} -void _EXX(struct s_assenv *ae) { - if (ae->wl[ae->idx].t==1) { - ___output(ae,0xD9); - ae->nop+=1; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"EXX does not need parameter\n"); - } -} -void _HALT(struct s_assenv *ae) { - if (ae->wl[ae->idx].t==1) { - ___output(ae,0x76); - ae->nop+=1; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"HALT does not need parameter\n"); - } -} - -void _RLA(struct s_assenv *ae) { - if (ae->wl[ae->idx].t==1) { - ___output(ae,0x17); - ae->nop+=1; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RLA does not need parameter\n"); - } -} -void _RRA(struct s_assenv *ae) { - if (ae->wl[ae->idx].t==1) { - ___output(ae,0x1F); - ae->nop+=1; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RRA does not need parameter\n"); - } -} -void _RLD(struct s_assenv *ae) { - if (ae->wl[ae->idx].t==1) { - ___output(ae,0xED); - ___output(ae,0x6F); - ae->nop+=5; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RLD does not need parameter\n"); - } -} -void _RRD(struct s_assenv *ae) { - if (ae->wl[ae->idx].t==1) { - ___output(ae,0xED); - ___output(ae,0x67); - ae->nop+=5; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RRD does not need parameter\n"); - } -} - - -void _EXA(struct s_assenv *ae) { - if (ae->wl[ae->idx].t==1) { - ___output(ae,0x08);ae->nop+=1; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"EXA alias does not need parameter\n"); - } -} - -void _NOP(struct s_assenv *ae) { - int o; - - if (ae->wl[ae->idx].t) { - ___output(ae,0x00); - ae->nop+=1; - } else if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - o=RoundComputeExpressionCore(ae,ae->wl[ae->idx+1].w,ae->codeadr,0); - if (o>=0) { - while (o>0) { - ___output(ae,0x00); - ae->nop+=1; - o--; - } - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"NOP is supposed to be used without parameter or with one optional parameter\n"); - } -} -void _DI(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0xF3); - ae->nop+=1; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DI does not need parameter\n"); - } -} -void _EI(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___output(ae,0xFB); - ae->nop+=1; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"EI does not need parameter\n"); - } -} - -void _RST(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t!=2) { - if (!strcmp(ae->wl[ae->idx+1].w,"(IY)") || !strcmp(ae->wl[ae->idx+1].w,"(IX)")) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RST cannot use IX or IY\n"); - } else { - /* la valeur du parametre va definir l'opcode du RST */ - PushExpression(ae,ae->idx+1,E_EXPRESSION_RST); - } - ae->idx++; - ae->nop+=4; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RST need one parameter\n"); - } -} - -void _DJNZ(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - if (IsRegister(ae->wl[ae->idx+1].w)) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DJNZ cannot use register\n"); - } else if (strcmp("(IX)",ae->wl[ae->idx+1].w)==0 || strcmp("(IY)",ae->wl[ae->idx+1].w)==0) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DJNZ cannot use register\n"); - } else { - ___output(ae,0x10); - PushExpression(ae,ae->idx+1,E_EXPRESSION_J8); - ae->nop+=3; - } - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DJNZ need one parameter\n"); - } -} - -void _LD(struct s_assenv *ae) { - /* on check qu'il y a au moins deux parametres */ - if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_A: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_I:___output(ae,0xED);___output(ae,0x57);ae->nop+=3;break; - case CRC_R:___output(ae,0xED);___output(ae,0x5F);ae->nop+=3;break; - case CRC_B:___output(ae,0x78);ae->nop+=1;break; - case CRC_C:___output(ae,0x79);ae->nop+=1;break; - case CRC_D:___output(ae,0x7A);ae->nop+=1;break; - case CRC_E:___output(ae,0x7B);ae->nop+=1;break; - case CRC_H:___output(ae,0x7C);ae->nop+=1;break; - case CRC_L:___output(ae,0x7D);ae->nop+=1;break; - case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x7C);ae->nop+=2;break; - case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x7D);ae->nop+=2;break; - case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x7C);ae->nop+=2;break; - case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x7D);ae->nop+=2;break; - case CRC_MHL:___output(ae,0x7E);ae->nop+=2;break; - case CRC_A:___output(ae,0x7F);ae->nop+=1;break; - case CRC_MBC:___output(ae,0x0A);ae->nop+=2;break; - case CRC_MDE:___output(ae,0x1A);ae->nop+=2;break; - default: - /* (ix+expression) (iy+expression) (expression) expression */ - if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,0x7E); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - ae->nop+=5; - } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,0x7E); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - ae->nop+=5; - } else if (StringIsMem(ae->wl[ae->idx+2].w)) { - ___output(ae,0x3A); - PushExpression(ae,ae->idx+2,E_EXPRESSION_V16); - ae->nop+=4; - } else { - ___output(ae,0x3E); - PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); - ae->nop+=2; - } - } - break; - case CRC_I: - if (GetCRC(ae->wl[ae->idx+2].w)==CRC_A) { - ___output(ae,0xED);___output(ae,0x47); - ae->nop+=3; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD I,A only\n"); - } - break; - case CRC_R: - if (GetCRC(ae->wl[ae->idx+2].w)==CRC_A) { - ___output(ae,0xED);___output(ae,0x4F); - ae->nop+=3; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD R,A only\n"); - } - break; - case CRC_B: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_B:___output(ae,0x40);ae->nop+=1;break; - case CRC_C:___output(ae,0x41);ae->nop+=1;break; - case CRC_D:___output(ae,0x42);ae->nop+=1;break; - case CRC_E:___output(ae,0x43);ae->nop+=1;break; - case CRC_H:___output(ae,0x44);ae->nop+=1;break; - case CRC_L:___output(ae,0x45);ae->nop+=1;break; - case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x44);ae->nop+=2;break; - case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x45);ae->nop+=2;break; - case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x44);ae->nop+=2;break; - case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x45);ae->nop+=2;break; - case CRC_MHL:___output(ae,0x46);ae->nop+=2;break; - case CRC_A:___output(ae,0x47);ae->nop+=1;break; - default: - /* (ix+expression) (iy+expression) expression */ - if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,0x46); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - ae->nop+=5; - } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,0x46); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - ae->nop+=5; - } else { - ___output(ae,0x06); - PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); - ae->nop+=2; - } - } - break; - case CRC_C: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_B:___output(ae,0x48);ae->nop+=1;break; - case CRC_C:___output(ae,0x49);ae->nop+=1;break; - case CRC_D:___output(ae,0x4A);ae->nop+=1;break; - case CRC_E:___output(ae,0x4B);ae->nop+=1;break; - case CRC_H:___output(ae,0x4C);ae->nop+=1;break; - case CRC_L:___output(ae,0x4D);ae->nop+=1;break; - case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x4C);ae->nop+=2;break; - case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x4D);ae->nop+=2;break; - case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x4C);ae->nop+=2;break; - case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x4D);ae->nop+=2;break; - case CRC_MHL:___output(ae,0x4E);ae->nop+=2;break; - case CRC_A:___output(ae,0x4F);ae->nop+=1;break; - default: - /* (ix+expression) (iy+expression) expression */ - if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,0x4E); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - ae->nop+=5; - } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,0x4E); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - ae->nop+=5; - } else { - ___output(ae,0x0E); - PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); - ae->nop+=2; - } - } - break; - case CRC_D: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_B:___output(ae,0x50);ae->nop+=1;break; - case CRC_C:___output(ae,0x51);ae->nop+=1;break; - case CRC_D:___output(ae,0x52);ae->nop+=1;break; - case CRC_E:___output(ae,0x53);ae->nop+=1;break; - case CRC_H:___output(ae,0x54);ae->nop+=1;break; - case CRC_L:___output(ae,0x55);ae->nop+=1;break; - case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x54);ae->nop+=2;break; - case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x55);ae->nop+=2;break; - case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x54);ae->nop+=2;break; - case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x55);ae->nop+=2;break; - case CRC_MHL:___output(ae,0x56);ae->nop+=2;break; - case CRC_A:___output(ae,0x57);ae->nop+=1;break; - default: - /* (ix+expression) (iy+expression) expression */ - if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,0x56); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - ae->nop+=5; - } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,0x56); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - ae->nop+=5; - } else { - ___output(ae,0x16); - PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); - ae->nop+=2; - } - } - break; - case CRC_E: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_B:___output(ae,0x58);ae->nop+=1;break; - case CRC_C:___output(ae,0x59);ae->nop+=1;break; - case CRC_D:___output(ae,0x5A);ae->nop+=1;break; - case CRC_E:___output(ae,0x5B);ae->nop+=1;break; - case CRC_H:___output(ae,0x5C);ae->nop+=1;break; - case CRC_L:___output(ae,0x5D);ae->nop+=1;break; - case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x5C);ae->nop+=2;break; - case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x5D);ae->nop+=2;break; - case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x5C);ae->nop+=2;break; - case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x5D);ae->nop+=2;break; - case CRC_MHL:___output(ae,0x5E);ae->nop+=2;break; - case CRC_A:___output(ae,0x5F);ae->nop+=1;break; - default: - /* (ix+expression) (iy+expression) expression */ - if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,0x5E); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - ae->nop+=5; - } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,0x5E); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - ae->nop+=5; - } else { - ___output(ae,0x1E); - PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); - ae->nop+=2; - } - } - break; - case CRC_IYH:case CRC_HY:case CRC_YH: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_B:___output(ae,0xFD);___output(ae,0x60);ae->nop+=2;break; - case CRC_C:___output(ae,0xFD);___output(ae,0x61);ae->nop+=2;break; - case CRC_D:___output(ae,0xFD);___output(ae,0x62);ae->nop+=2;break; - case CRC_E:___output(ae,0xFD);___output(ae,0x63);ae->nop+=2;break; - case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x64);ae->nop+=2;break; - case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x65);ae->nop+=2;break; - case CRC_A:___output(ae,0xFD);___output(ae,0x67);ae->nop+=2;break; - default: - ___output(ae,0xFD);___output(ae,0x26); - PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); - ae->nop+=3; - } - break; - case CRC_IYL:case CRC_LY:case CRC_YL: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_B:___output(ae,0xFD);___output(ae,0x68);ae->nop+=2;break; - case CRC_C:___output(ae,0xFD);___output(ae,0x69);ae->nop+=2;break; - case CRC_D:___output(ae,0xFD);___output(ae,0x6A);ae->nop+=2;break; - case CRC_E:___output(ae,0xFD);___output(ae,0x6B);ae->nop+=2;break; - case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x6C);ae->nop+=2;break; - case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x6D);ae->nop+=2;break; - case CRC_A:___output(ae,0xFD);___output(ae,0x6F);ae->nop+=2;break; - default: - ___output(ae,0xFD);___output(ae,0x2E); - PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); - ae->nop+=3; - } - break; - case CRC_IXH:case CRC_HX:case CRC_XH: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_B:___output(ae,0xDD);___output(ae,0x60);ae->nop+=2;break; - case CRC_C:___output(ae,0xDD);___output(ae,0x61);ae->nop+=2;break; - case CRC_D:___output(ae,0xDD);___output(ae,0x62);ae->nop+=2;break; - case CRC_E:___output(ae,0xDD);___output(ae,0x63);ae->nop+=2;break; - case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x64);ae->nop+=2;break; - case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x65);ae->nop+=2;break; - case CRC_A:___output(ae,0xDD);___output(ae,0x67);ae->nop+=2;break; - default: - ___output(ae,0xDD);___output(ae,0x26); - PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); - ae->nop+=3; - } - break; - case CRC_IXL:case CRC_LX:case CRC_XL: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_B:___output(ae,0xDD);___output(ae,0x68);ae->nop+=2;break; - case CRC_C:___output(ae,0xDD);___output(ae,0x69);ae->nop+=2;break; - case CRC_D:___output(ae,0xDD);___output(ae,0x6A);ae->nop+=2;break; - case CRC_E:___output(ae,0xDD);___output(ae,0x6B);ae->nop+=2;break; - case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x6C);ae->nop+=2;break; - case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x6D);ae->nop+=2;break; - case CRC_A:___output(ae,0xDD);___output(ae,0x6F);ae->nop+=2;break; - default: - ___output(ae,0xDD);___output(ae,0x2E); - PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); - ae->nop+=3; - } - break; - case CRC_H: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_B:___output(ae,0x60);ae->nop+=1;break; - case CRC_C:___output(ae,0x61);ae->nop+=1;break; - case CRC_D:___output(ae,0x62);ae->nop+=1;break; - case CRC_E:___output(ae,0x63);ae->nop+=1;break; - case CRC_H:___output(ae,0x64);ae->nop+=1;break; - case CRC_L:___output(ae,0x65);ae->nop+=1;break; - case CRC_MHL:___output(ae,0x66);ae->nop+=2;break; - case CRC_A:___output(ae,0x67);ae->nop+=1;break; - default: - /* (ix+expression) (iy+expression) expression */ - if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,0x66); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - ae->nop+=5; - } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,0x66); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - ae->nop+=5; - } else { - ___output(ae,0x26); - PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); - ae->nop+=2; - } - } - break; - case CRC_L: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_B:___output(ae,0x68);ae->nop+=1;break; - case CRC_C:___output(ae,0x69);ae->nop+=1;break; - case CRC_D:___output(ae,0x6A);ae->nop+=1;break; - case CRC_E:___output(ae,0x6B);ae->nop+=1;break; - case CRC_H:___output(ae,0x6C);ae->nop+=1;break; - case CRC_L:___output(ae,0x6D);ae->nop+=1;break; - case CRC_MHL:___output(ae,0x6E);ae->nop+=2;break; - case CRC_A:___output(ae,0x6F);ae->nop+=1;break; - default: - /* (ix+expression) (iy+expression) expression */ - if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,0x6E); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - ae->nop+=5; - } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,0x6E); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - ae->nop+=5; - } else { - ___output(ae,0x2E); - PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); - ae->nop+=2; - } - } - break; - case CRC_MHL: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_B:___output(ae,0x70);ae->nop+=2;break; - case CRC_C:___output(ae,0x71);ae->nop+=2;break; - case CRC_D:___output(ae,0x72);ae->nop+=2;break; - case CRC_E:___output(ae,0x73);ae->nop+=2;break; - case CRC_H:___output(ae,0x74);ae->nop+=2;break; - case CRC_L:___output(ae,0x75);ae->nop+=2;break; - case CRC_A:___output(ae,0x77);ae->nop+=2;break; - default: - /* expression */ - ___output(ae,0x36); - PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); - ae->nop+=3; - } - break; - case CRC_MBC: - if (GetCRC(ae->wl[ae->idx+2].w)==CRC_A) { - ___output(ae,0x02); - ae->nop+=2; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD (BC),A only\n"); - } - break; - case CRC_MDE: - if (GetCRC(ae->wl[ae->idx+2].w)==CRC_A) { - ___output(ae,0x12); - ae->nop+=2; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD (DE),A only\n"); - } - break; - case CRC_HL: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_BC:___output(ae,0x60);___output(ae,0x69);ae->nop+=2;break; - case CRC_DE:___output(ae,0x62);___output(ae,0x6B);ae->nop+=2;break; - case CRC_HL:___output(ae,0x64);___output(ae,0x6D);ae->nop+=2;break; - default: - if (strncmp(ae->wl[ae->idx+2].w,"(IX+",4)==0) { - /* enhanced LD HL,(IX+nn) */ - ___output(ae,0xDD);___output(ae,0x66); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV81); - ___output(ae,0xDD);___output(ae,0x6E); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - ae->nop+=10; - } else if (strncmp(ae->wl[ae->idx+2].w,"(IY+",4)==0) { - /* enhanced LD HL,(IY+nn) */ - ___output(ae,0xFD);___output(ae,0x66); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV81); - ___output(ae,0xFD);___output(ae,0x6E); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - ae->nop+=10; - } else if (StringIsMem(ae->wl[ae->idx+2].w)) { - ___output(ae,0x2A); - PushExpression(ae,ae->idx+2,E_EXPRESSION_V16); - ae->nop+=5; - } else { - ___output(ae,0x21); - PushExpression(ae,ae->idx+2,E_EXPRESSION_V16); - ae->nop+=3; - } - } - break; - case CRC_BC: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_BC:___output(ae,0x40);___output(ae,0x49);ae->nop+=2;break; - case CRC_DE:___output(ae,0x42);___output(ae,0x4B);ae->nop+=2;break; - case CRC_HL:___output(ae,0x44);___output(ae,0x4D);ae->nop+=2;break; - default: - if (strncmp(ae->wl[ae->idx+2].w,"(IX+",4)==0) { - /* enhanced LD BC,(IX+nn) */ - ___output(ae,0xDD);___output(ae,0x46); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV81); - ___output(ae,0xDD);___output(ae,0x4E); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - ae->nop+=10; - } else if (strncmp(ae->wl[ae->idx+2].w,"(IY+",4)==0) { - /* enhanced LD BC,(IY+nn) */ - ___output(ae,0xFD);___output(ae,0x46); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV81); - ___output(ae,0xFD);___output(ae,0x4E); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - ae->nop+=10; - } else if (StringIsMem(ae->wl[ae->idx+2].w)) { - ___output(ae,0xED);___output(ae,0x4B); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV16); - ae->nop+=6; - } else { - ___output(ae,0x01); - PushExpression(ae,ae->idx+2,E_EXPRESSION_V16); - ae->nop+=3; - } - } - break; - case CRC_DE: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_BC:___output(ae,0x50);___output(ae,0x59);ae->nop+=2;break; - case CRC_DE:___output(ae,0x52);___output(ae,0x5B);ae->nop+=2;break; - case CRC_HL:___output(ae,0x54);___output(ae,0x5D);ae->nop+=2;break; - default: - if (strncmp(ae->wl[ae->idx+2].w,"(IX+",4)==0) { - /* enhanced LD DE,(IX+nn) */ - ___output(ae,0xDD);___output(ae,0x56); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV81); - ___output(ae,0xDD);___output(ae,0x5E); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - ae->nop+=10; - } else if (strncmp(ae->wl[ae->idx+2].w,"(IY+",4)==0) { - /* enhanced LD DE,(IY+nn) */ - ___output(ae,0xFD);___output(ae,0x56); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV81); - ___output(ae,0xFD);___output(ae,0x5E); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - ae->nop+=10; - } else if (StringIsMem(ae->wl[ae->idx+2].w)) { - ___output(ae,0xED);___output(ae,0x5B); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV16); - ae->nop+=6; - } else { - ___output(ae,0x11); - PushExpression(ae,ae->idx+2,E_EXPRESSION_V16); - ae->nop+=3; - } - } - break; - case CRC_IX: - if (StringIsMem(ae->wl[ae->idx+2].w)) { - ___output(ae,0xDD);___output(ae,0x2A); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV16); - ae->nop+=6; - } else { - ___output(ae,0xDD);___output(ae,0x21); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV16); - ae->nop+=4; - } - break; - case CRC_IY: - if (StringIsMem(ae->wl[ae->idx+2].w)) { - ___output(ae,0xFD);___output(ae,0x2A); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV16); - ae->nop+=6; - } else { - ___output(ae,0xFD);___output(ae,0x21); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV16); - ae->nop+=4; - } - break; - case CRC_SP: - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_HL:___output(ae,0xF9);ae->nop+=2;break; - case CRC_IX:___output(ae,0xDD);___output(ae,0xF9);ae->nop+=3;break; - case CRC_IY:___output(ae,0xFD);___output(ae,0xF9);ae->nop+=3;break; - default: - if (StringIsMem(ae->wl[ae->idx+2].w)) { - ___output(ae,0xED);___output(ae,0x7B); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV16); - ae->nop+=6; - } else { - ___output(ae,0x31); - PushExpression(ae,ae->idx+2,E_EXPRESSION_V16); - ae->nop+=3; - } - } - break; - default: - /* (ix+expression) (iy+expression) (expression) expression */ - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_B:___output(ae,0xDD);___output(ae,0x70);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; - case CRC_C:___output(ae,0xDD);___output(ae,0x71);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; - case CRC_D:___output(ae,0xDD);___output(ae,0x72);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; - case CRC_E:___output(ae,0xDD);___output(ae,0x73);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; - case CRC_H:___output(ae,0xDD);___output(ae,0x74);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; - case CRC_L:___output(ae,0xDD);___output(ae,0x75);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; - case CRC_A:___output(ae,0xDD);___output(ae,0x77);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; - case CRC_HL:___output(ae,0xDD);___output(ae,0x74);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV81);___output(ae,0xDD);___output(ae,0x75);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=10;break; - case CRC_DE:___output(ae,0xDD);___output(ae,0x72);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV81);___output(ae,0xDD);___output(ae,0x73);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=10;break; - case CRC_BC:___output(ae,0xDD);___output(ae,0x70);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV81);___output(ae,0xDD);___output(ae,0x71);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=10;break; - default:___output(ae,0xDD);___output(ae,0x36); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - PushExpression(ae,ae->idx+2,E_EXPRESSION_3V8); - ae->nop+=6; - } - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_B:___output(ae,0xFD);___output(ae,0x70);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; - case CRC_C:___output(ae,0xFD);___output(ae,0x71);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; - case CRC_D:___output(ae,0xFD);___output(ae,0x72);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; - case CRC_E:___output(ae,0xFD);___output(ae,0x73);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; - case CRC_H:___output(ae,0xFD);___output(ae,0x74);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; - case CRC_L:___output(ae,0xFD);___output(ae,0x75);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; - case CRC_A:___output(ae,0xFD);___output(ae,0x77);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; - case CRC_HL:___output(ae,0xFD);___output(ae,0x74);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV81);___output(ae,0xFD);___output(ae,0x75);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=10;break; - case CRC_DE:___output(ae,0xFD);___output(ae,0x72);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV81);___output(ae,0xFD);___output(ae,0x73);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=10;break; - case CRC_BC:___output(ae,0xFD);___output(ae,0x70);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV81);___output(ae,0xFD);___output(ae,0x71);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=10;break; - default:___output(ae,0xFD);___output(ae,0x36); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - PushExpression(ae,ae->idx+2,E_EXPRESSION_3V8); - ae->nop+=6; - } - } else if (StringIsMem(ae->wl[ae->idx+1].w)) { - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_A:___output(ae,0x32);PushExpression(ae,ae->idx+1,E_EXPRESSION_V16);ae->nop+=4;break; - case CRC_BC:___output(ae,0xED);___output(ae,0x43);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV16);ae->nop+=6;break; - case CRC_DE:___output(ae,0xED);___output(ae,0x53);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV16);ae->nop+=6;break; - case CRC_HL:___output(ae,0x22);PushExpression(ae,ae->idx+1,E_EXPRESSION_V16);ae->nop+=5;break; - case CRC_IX:___output(ae,0xDD);___output(ae,0x22);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV16);ae->nop+=6;break; - case CRC_IY:___output(ae,0xFD);___output(ae,0x22);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV16);ae->nop+=6;break; - case CRC_SP:___output(ae,0xED);___output(ae,0x73);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV16);ae->nop+=6;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD (#nnnn),[A,BC,DE,HL,SP,IX,IY] only\n"); - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Unknown LD format\n"); - } - break; - } - ae->idx+=2; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD needs two parameters\n"); - } -} - - -void _RLC(struct s_assenv *ae) { - /* on check qu'il y a un ou deux parametres */ - if (ae->wl[ae->idx+1].t==1) { - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_B:___output(ae,0xCB);___output(ae,0x0);ae->nop+=2;break; - case CRC_C:___output(ae,0xCB);___output(ae,0x1);ae->nop+=2;break; - case CRC_D:___output(ae,0xCB);___output(ae,0x2);ae->nop+=2;break; - case CRC_E:___output(ae,0xCB);___output(ae,0x3);ae->nop+=2;break; - case CRC_H:___output(ae,0xCB);___output(ae,0x4);ae->nop+=2;break; - case CRC_L:___output(ae,0xCB);___output(ae,0x5);ae->nop+=2;break; - case CRC_MHL:___output(ae,0xCB);___output(ae,0x6);ae->nop+=4;break; - case CRC_A:___output(ae,0xCB);___output(ae,0x7);ae->nop+=2;break; - default: - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,0xCB); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ___output(ae,0x6); - ae->nop+=7; - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,0xCB); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ___output(ae,0x6); - ae->nop+=7; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RLC reg8/(HL)/(IX+n)/(IY+n)\n"); - } - } - ae->idx++; - } else if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD); - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RLC (IX+n),reg8\n"); - } - ___output(ae,0xCB); - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_B:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x0);ae->nop+=7;break; - case CRC_C:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x1);ae->nop+=7;break; - case CRC_D:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x2);ae->nop+=7;break; - case CRC_E:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x3);ae->nop+=7;break; - case CRC_H:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x4);ae->nop+=7;break; - case CRC_L:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x5);ae->nop+=7;break; - case CRC_A:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x7);ae->nop+=7;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RLC (IX+n),reg8\n"); - } - ae->idx++; - ae->idx++; - } -} - -void _RRC(struct s_assenv *ae) { - /* on check qu'il y a un ou deux parametres */ - if (ae->wl[ae->idx+1].t==1) { - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_B:___output(ae,0xCB);___output(ae,0x8);ae->nop+=2;break; - case CRC_C:___output(ae,0xCB);___output(ae,0x9);ae->nop+=2;break; - case CRC_D:___output(ae,0xCB);___output(ae,0xA);ae->nop+=2;break; - case CRC_E:___output(ae,0xCB);___output(ae,0xB);ae->nop+=2;break; - case CRC_H:___output(ae,0xCB);___output(ae,0xC);ae->nop+=2;break; - case CRC_L:___output(ae,0xCB);___output(ae,0xD);ae->nop+=2;break; - case CRC_MHL:___output(ae,0xCB);___output(ae,0xE);ae->nop+=4;break; - case CRC_A:___output(ae,0xCB);___output(ae,0xF);ae->nop+=2;break; - default: - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,0xCB); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ___output(ae,0xE); - ae->nop+=7; - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,0xCB); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ___output(ae,0xE); - ae->nop+=7; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RRC reg8/(HL)/(IX+n)/(IY+n)\n"); - } - } - ae->idx++; - } else if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD); - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RRC (IX+n),reg8\n"); - } - ___output(ae,0xCB); - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_B:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x8);ae->nop+=7;break; - case CRC_C:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x9);ae->nop+=7;break; - case CRC_D:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0xA);ae->nop+=7;break; - case CRC_E:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0xB);ae->nop+=7;break; - case CRC_H:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0xC);ae->nop+=7;break; - case CRC_L:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0xD);ae->nop+=7;break; - case CRC_A:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0xF);ae->nop+=7;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RRC (IX+n),reg8\n"); - } - ae->idx++; - ae->idx++; - } -} - - -void _RL(struct s_assenv *ae) { - /* on check qu'il y a un ou deux parametres */ - if (ae->wl[ae->idx+1].t==1) { - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_BC:___output(ae,0xCB);___output(ae,0x10);___output(ae,0xCB);___output(ae,0x11);ae->nop+=4;break; - case CRC_B:___output(ae,0xCB);___output(ae,0x10);ae->nop+=2;break; - case CRC_C:___output(ae,0xCB);___output(ae,0x11);ae->nop+=2;break; - case CRC_DE:___output(ae,0xCB);___output(ae,0x12);___output(ae,0xCB);___output(ae,0x13);ae->nop+=4;break; - case CRC_D:___output(ae,0xCB);___output(ae,0x12);ae->nop+=2;break; - case CRC_E:___output(ae,0xCB);___output(ae,0x13);ae->nop+=2;break; - case CRC_HL:___output(ae,0xCB);___output(ae,0x14);___output(ae,0xCB);___output(ae,0x15);ae->nop+=4;break; - case CRC_H:___output(ae,0xCB);___output(ae,0x14);ae->nop+=2;break; - case CRC_L:___output(ae,0xCB);___output(ae,0x15);ae->nop+=2;break; - case CRC_MHL:___output(ae,0xCB);___output(ae,0x16);ae->nop+=4;break; - case CRC_A:___output(ae,0xCB);___output(ae,0x17);ae->nop+=2;break; - default: - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,0xCB); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ___output(ae,0x16); - ae->nop+=7; - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,0xCB); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ___output(ae,0x16); - ae->nop+=7; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RL reg8/(HL)/(IX+n)/(IY+n)\n"); - } - } - ae->idx++; - } else if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD); - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RL (IX+n),reg8\n"); - } - ___output(ae,0xCB); - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_B:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x10);ae->nop+=7;break; - case CRC_C:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x11);ae->nop+=7;break; - case CRC_D:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x12);ae->nop+=7;break; - case CRC_E:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x13);ae->nop+=7;break; - case CRC_H:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x14);ae->nop+=7;break; - case CRC_L:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x15);ae->nop+=7;break; - case CRC_A:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x17);ae->nop+=7;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RL (IX+n),reg8\n"); - } - ae->idx++; - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RL (IX+n),reg8 or RL reg8/(HL)/(IX+n)/(IY+n)\n"); - } -} - -void _RR(struct s_assenv *ae) { - /* on check qu'il y a un ou deux parametres */ - if (ae->wl[ae->idx+1].t==1) { - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_BC:___output(ae,0xCB);___output(ae,0x18);___output(ae,0xCB);___output(ae,0x19);ae->nop+=4;break; - case CRC_B:___output(ae,0xCB);___output(ae,0x18);ae->nop+=2;break; - case CRC_C:___output(ae,0xCB);___output(ae,0x19);ae->nop+=2;break; - case CRC_DE:___output(ae,0xCB);___output(ae,0x1A);___output(ae,0xCB);___output(ae,0x1B);ae->nop+=4;break; - case CRC_D:___output(ae,0xCB);___output(ae,0x1A);ae->nop+=2;break; - case CRC_E:___output(ae,0xCB);___output(ae,0x1B);ae->nop+=2;break; - case CRC_HL:___output(ae,0xCB);___output(ae,0x1C);___output(ae,0xCB);___output(ae,0x1D);ae->nop+=4;break; - case CRC_H:___output(ae,0xCB);___output(ae,0x1C);ae->nop+=2;break; - case CRC_L:___output(ae,0xCB);___output(ae,0x1D);ae->nop+=2;break; - case CRC_MHL:___output(ae,0xCB);___output(ae,0x1E);ae->nop+=4;break; - case CRC_A:___output(ae,0xCB);___output(ae,0x1F);ae->nop+=2;break; - default: - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,0xCB); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ___output(ae,0x1E); - ae->nop+=7; - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,0xCB); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ___output(ae,0x1E); - ae->nop+=7; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RR reg8/(HL)/(IX+n)/(IY+n)\n"); - } - } - ae->idx++; - } else if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD); - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RR (IX+n),reg8\n"); - } - ___output(ae,0xCB); - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_B:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x18);ae->nop+=7;break; - case CRC_C:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x19);ae->nop+=7;break; - case CRC_D:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x1A);ae->nop+=7;break; - case CRC_E:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x1B);ae->nop+=7;break; - case CRC_H:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x1C);ae->nop+=7;break; - case CRC_L:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x1D);ae->nop+=7;break; - case CRC_A:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x1F);ae->nop+=7;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RR (IX+n),reg8\n"); - } - ae->idx++; - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RR (IX+n),reg8 or RR reg8/(HL)/(IX+n)/(IY+n)\n"); - } -} - - - - - -void _SLA(struct s_assenv *ae) { - /* on check qu'il y a un ou deux parametres */ - if (ae->wl[ae->idx+1].t==1) { - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_BC:___output(ae,0xCB);___output(ae,0x21);___output(ae,0xCB);___output(ae,0x10);ae->nop+=4;break; /* SLA C : RL B */ - case CRC_B:___output(ae,0xCB);___output(ae,0x20);ae->nop+=2;break; - case CRC_C:___output(ae,0xCB);___output(ae,0x21);ae->nop+=2;break; - case CRC_DE:___output(ae,0xCB);___output(ae,0x23);___output(ae,0xCB);___output(ae,0x12);ae->nop+=4;break; /* SLA E : RL D */ - case CRC_D:___output(ae,0xCB);___output(ae,0x22);ae->nop+=2;break; - case CRC_E:___output(ae,0xCB);___output(ae,0x23);ae->nop+=2;break; - case CRC_HL:___output(ae,0xCB);___output(ae,0x25);___output(ae,0xCB);___output(ae,0x14);ae->nop+=4;break; /* SLA L : RL H */ - case CRC_H:___output(ae,0xCB);___output(ae,0x24);ae->nop+=2;break; - case CRC_L:___output(ae,0xCB);___output(ae,0x25);ae->nop+=2;break; - case CRC_MHL:___output(ae,0xCB);___output(ae,0x26);ae->nop+=4;break; - case CRC_A:___output(ae,0xCB);___output(ae,0x27);ae->nop+=2;break; - default: - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,0xCB); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ___output(ae,0x26); - ae->nop+=7; - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,0xCB); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ___output(ae,0x26); - ae->nop+=7; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SLA reg8/(HL)/(IX+n)/(IY+n)\n"); - } - } - ae->idx++; - } else if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD); - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SLL (IX+n),reg8\n"); - } - ___output(ae,0xCB); - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_B:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x20);ae->nop+=7;break; - case CRC_C:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x21);ae->nop+=7;break; - case CRC_D:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x22);ae->nop+=7;break; - case CRC_E:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x23);ae->nop+=7;break; - case CRC_H:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x24);ae->nop+=7;break; - case CRC_L:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x25);ae->nop+=7;break; - case CRC_A:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x27);ae->nop+=7;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SLA (IX+n),reg8\n"); - } - ae->idx++; - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SLA reg8/(HL)/(IX+n)/(IY+n) or SLA (IX+n),reg8\n"); - } -} - -void _SRA(struct s_assenv *ae) { - /* on check qu'il y a un ou deux parametres */ - if (ae->wl[ae->idx+1].t==1) { - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_BC:___output(ae,0xCB);___output(ae,0x28);___output(ae,0xCB);___output(ae,0x19);ae->nop+=4;break; /* SRA B : RR C */ - case CRC_B:___output(ae,0xCB);___output(ae,0x28);ae->nop+=2;break; - case CRC_C:___output(ae,0xCB);___output(ae,0x29);ae->nop+=2;break; - case CRC_DE:___output(ae,0xCB);___output(ae,0x2A);___output(ae,0xCB);___output(ae,0x1B);ae->nop+=4;break; /* SRA D : RR E */ - case CRC_D:___output(ae,0xCB);___output(ae,0x2A);ae->nop+=2;break; - case CRC_E:___output(ae,0xCB);___output(ae,0x2B);ae->nop+=2;break; - case CRC_HL:___output(ae,0xCB);___output(ae,0x2C);___output(ae,0xCB);___output(ae,0x1D);ae->nop+=4;break; /* SRA H : RR L */ - case CRC_H:___output(ae,0xCB);___output(ae,0x2C);ae->nop+=2;break; - case CRC_L:___output(ae,0xCB);___output(ae,0x2D);ae->nop+=2;break; - case CRC_MHL:___output(ae,0xCB);___output(ae,0x2E);ae->nop+=4;break; - case CRC_A:___output(ae,0xCB);___output(ae,0x2F);ae->nop+=2;break; - default: - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,0xCB); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ___output(ae,0x2E); - ae->nop+=7; - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,0xCB); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ___output(ae,0x2E); - ae->nop+=7; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SRA reg8/(HL)/(IX+n)/(IY+n)\n"); - } - } - ae->idx++; - } else if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD); - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SRA (IX+n),reg8\n"); - } - ___output(ae,0xCB); - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_B:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x28);ae->nop+=7;break; - case CRC_C:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x29);ae->nop+=7;break; - case CRC_D:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x2A);ae->nop+=7;break; - case CRC_E:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x2B);ae->nop+=7;break; - case CRC_H:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x2C);ae->nop+=7;break; - case CRC_L:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x2D);ae->nop+=7;break; - case CRC_A:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x2F);ae->nop+=7;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SRA (IX+n),reg8\n"); - } - ae->idx++; - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SRA reg8/(HL)/(IX+n)/(IY+n) or SRA (IX+n),reg8\n"); - } -} - - -void _SLL(struct s_assenv *ae) { - /* on check qu'il y a un ou deux parametres */ - if (ae->wl[ae->idx+1].t==1) { - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_BC:___output(ae,0xCB);___output(ae,0x31);___output(ae,0xCB);___output(ae,0x10);ae->nop+=4;break; /* SLL C : RL B */ - case CRC_B:___output(ae,0xCB);___output(ae,0x30);ae->nop+=2;break; - case CRC_C:___output(ae,0xCB);___output(ae,0x31);ae->nop+=2;break; - case CRC_DE:___output(ae,0xCB);___output(ae,0x33);___output(ae,0xCB);___output(ae,0x12);ae->nop+=4;break; /* SLL E : RL D */ - case CRC_D:___output(ae,0xCB);___output(ae,0x32);ae->nop+=2;break; - case CRC_E:___output(ae,0xCB);___output(ae,0x33);ae->nop+=2;break; - case CRC_HL:___output(ae,0xCB);___output(ae,0x35);___output(ae,0xCB);___output(ae,0x14);ae->nop+=4;break; /* SLL L : RL H */ - case CRC_H:___output(ae,0xCB);___output(ae,0x34);ae->nop+=2;break; - case CRC_L:___output(ae,0xCB);___output(ae,0x35);ae->nop+=2;break; - case CRC_MHL:___output(ae,0xCB);___output(ae,0x36);ae->nop+=4;break; - case CRC_A:___output(ae,0xCB);___output(ae,0x37);ae->nop+=2;break; - default: - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,0xCB); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ___output(ae,0x36); - ae->nop+=7; - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,0xCB); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ___output(ae,0x36); - ae->nop+=7; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SLL reg8/(HL)/(IX+n)/(IY+n)\n"); - } - } - ae->idx++; - } else if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD); - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SLL (IX+n),reg8\n"); - } - ___output(ae,0xCB); - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_B:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x30);ae->nop+=7;break; - case CRC_C:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x31);ae->nop+=7;break; - case CRC_D:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x32);ae->nop+=7;break; - case CRC_E:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x33);ae->nop+=7;break; - case CRC_H:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x34);ae->nop+=7;break; - case CRC_L:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x35);ae->nop+=7;break; - case CRC_A:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x37);ae->nop+=7;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SLL (IX+n),reg8\n"); - } - ae->idx++; - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SLL reg8/(HL)/(IX+n)/(IY+n) or SLL (IX+n),reg8\n"); - } -} - -void _SRL(struct s_assenv *ae) { - /* on check qu'il y a un ou deux parametres */ - if (ae->wl[ae->idx+1].t==1) { - switch (GetCRC(ae->wl[ae->idx+1].w)) { - case CRC_BC:___output(ae,0xCB);___output(ae,0x38);___output(ae,0xCB);___output(ae,0x11);ae->nop+=4;break; /* SRL B : RL C */ - case CRC_B:___output(ae,0xCB);___output(ae,0x38);ae->nop+=2;break; - case CRC_C:___output(ae,0xCB);___output(ae,0x39);ae->nop+=2;break; - case CRC_DE:___output(ae,0xCB);___output(ae,0x3A);___output(ae,0xCB);___output(ae,0x13);ae->nop+=4;break; /* SRL D : RL E */ - case CRC_D:___output(ae,0xCB);___output(ae,0x3A);ae->nop+=2;break; - case CRC_E:___output(ae,0xCB);___output(ae,0x3B);ae->nop+=2;break; - case CRC_HL:___output(ae,0xCB);___output(ae,0x3C);___output(ae,0xCB);___output(ae,0x15);ae->nop+=4;break; /* SRL H : RL L */ - case CRC_H:___output(ae,0xCB);___output(ae,0x3C);ae->nop+=2;break; - case CRC_L:___output(ae,0xCB);___output(ae,0x3D);ae->nop+=2;break; - case CRC_MHL:___output(ae,0xCB);___output(ae,0x3E);ae->nop+=4;break; - case CRC_A:___output(ae,0xCB);___output(ae,0x3F);ae->nop+=2;break; - default: - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,0xCB); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ___output(ae,0x3E); - ae->nop+=7; - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,0xCB); - PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); - ___output(ae,0x3E); - ae->nop+=7; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SRL reg8/(HL)/(IX+n)/(IY+n)\n"); - } - } - ae->idx++; - } else if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { - if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { - ___output(ae,0xDD); - } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { - ___output(ae,0xFD); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SRL (IX+n),reg8\n"); - } - ___output(ae,0xCB); - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_B:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x38);ae->nop+=7;break; - case CRC_C:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x39);ae->nop+=7;break; - case CRC_D:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x3A);ae->nop+=7;break; - case CRC_E:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x3B);ae->nop+=7;break; - case CRC_H:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x3C);ae->nop+=7;break; - case CRC_L:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x3D);ae->nop+=7;break; - case CRC_A:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x3F);ae->nop+=7;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SRL (IX+n),reg8\n"); - } - ae->idx++; - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SRL reg8/(HL)/(IX+n)/(IY+n) or SRL (IX+n),reg8\n"); - } -} - - -void _BIT(struct s_assenv *ae) { - int o; - /* on check qu'il y a deux ou trois parametres - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - o=RoundComputeExpressionCore(ae,ae->wl[ae->idx+1].w,ae->codeadr,0);*/ - - o=0; - if (o<0 || o>7) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is BIT ,... (%d)\n",o); - } else { - o=0x40+o*8; - if (ae->wl[ae->idx+1].t==0 && ae->wl[ae->idx+2].t==1) { - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_B:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x0+o);ae->nop+=2;break; - case CRC_C:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x1+o);ae->nop+=2;break; - case CRC_D:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x2+o);ae->nop+=2;break; - case CRC_E:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x3+o);ae->nop+=2;break; - case CRC_H:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x4+o);ae->nop+=2;break; - case CRC_L:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x5+o);ae->nop+=2;break; - case CRC_MHL:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x6+o);ae->nop+=3;break; - case CRC_A:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x7+o);ae->nop+=2;break; - default: - if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,0xCB); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x6+o); - ae->nop+=6; - } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,0xCB); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x6+o); - ae->nop+=6; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is BIT n,reg8/(HL)/(IX+n)/(IY+n)\n"); - } - } - ae->idx+=2; - } else if (!ae->wl[ae->idx+1].t && !ae->wl[ae->idx+2].t && ae->wl[ae->idx+3].t==1) { - if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { - ___output(ae,0xDD); - } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { - ___output(ae,0xFD); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is BIT (IX+n),reg8\n"); - } - ___output(ae,0xCB); - switch (GetCRC(ae->wl[ae->idx+3].w)) { - case CRC_B:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x0+o);ae->nop+=6;break; - case CRC_C:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x1+o);ae->nop+=6;break; - case CRC_D:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x2+o);ae->nop+=6;break; - case CRC_E:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x3+o);ae->nop+=6;break; - case CRC_H:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x4+o);ae->nop+=6;break; - case CRC_L:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x5+o);ae->nop+=6;break; - case CRC_A:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x7+o);ae->nop+=6;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is BIT n,(IX+n),reg8\n"); - } - ae->idx+=3; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is BIT n,reg8/(HL)/(IX+n)[,reg8]/(IY+n)[,reg8]\n"); - } - } -} - -void _RES(struct s_assenv *ae) { - int o; - /* on check qu'il y a deux ou trois parametres - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - o=RoundComputeExpressionCore(ae,ae->wl[ae->idx+1].w,ae->codeadr,0); */ - o=0; - if (o<0 || o>7) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RES ,... (%d)\n",o); - } else { - o=0x80+o*8; - if (ae->wl[ae->idx+1].t==0 && ae->wl[ae->idx+2].t==1) { - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_B:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x0+o);ae->nop+=2;break; - case CRC_C:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x1+o);ae->nop+=2;break; - case CRC_D:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x2+o);ae->nop+=2;break; - case CRC_E:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x3+o);ae->nop+=2;break; - case CRC_H:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x4+o);ae->nop+=2;break; - case CRC_L:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x5+o);ae->nop+=2;break; - case CRC_MHL:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x6+o);ae->nop+=4;break; - case CRC_A:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x7+o);ae->nop+=2;break; - default: - if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,0xCB); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x6+o); - ae->nop+=7; - } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,0xCB); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x6+o); - ae->nop+=7; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RES n,reg8/(HL)/(IX+n)/(IY+n)\n"); - } - } - ae->idx+=2; - } else if (!ae->wl[ae->idx+1].t && !ae->wl[ae->idx+2].t && ae->wl[ae->idx+3].t==1) { - if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { - ___output(ae,0xDD); - } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { - ___output(ae,0xFD); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RES n,(IX+n),reg8\n"); - } - ___output(ae,0xCB); - switch (GetCRC(ae->wl[ae->idx+3].w)) { - case CRC_B:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x0+o);ae->nop+=7;break; - case CRC_C:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x1+o);ae->nop+=7;break; - case CRC_D:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x2+o);ae->nop+=7;break; - case CRC_E:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x3+o);ae->nop+=7;break; - case CRC_H:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x4+o);ae->nop+=7;break; - case CRC_L:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x5+o);ae->nop+=7;break; - case CRC_A:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x7+o);ae->nop+=7;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RES n,(IX+n),reg8\n"); - } - ae->idx+=3; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RES n,reg8/(HL)/(IX+n)[,reg8]/(IY+n)[,reg8]\n"); - } - } -} - -void _SET(struct s_assenv *ae) { - int o; - /* on check qu'il y a deux ou trois parametres - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - o=RoundComputeExpressionCore(ae,ae->wl[ae->idx+1].w,ae->codeadr,0); */ - o=0; - if (o<0 || o>7) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SET ,... (%d)\n",o); - } else { - o=0xC0+o*8; - if (ae->wl[ae->idx+1].t==0 && ae->wl[ae->idx+2].t==1) { - switch (GetCRC(ae->wl[ae->idx+2].w)) { - case CRC_B:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x0+o);ae->nop+=2;break; - case CRC_C:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x1+o);ae->nop+=2;break; - case CRC_D:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x2+o);ae->nop+=2;break; - case CRC_E:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x3+o);ae->nop+=2;break; - case CRC_H:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x4+o);ae->nop+=2;break; - case CRC_L:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x5+o);ae->nop+=2;break; - case CRC_MHL:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x6+o);ae->nop+=4;break; - case CRC_A:___output(ae,0xCB);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x7+o);ae->nop+=2;break; - default: - if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { - ___output(ae,0xDD);___output(ae,0xCB); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x6+o); - ae->nop+=7; - } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { - ___output(ae,0xFD);___output(ae,0xCB); - PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); - PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x6+o); - ae->nop+=7; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SET n,reg8/(HL)/(IX+n)/(IY+n)\n"); - } - } - ae->idx+=2; - } else if (!ae->wl[ae->idx+1].t && !ae->wl[ae->idx+2].t && ae->wl[ae->idx+3].t==1) { - if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { - ___output(ae,0xDD); - } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { - ___output(ae,0xFD); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SET n,(IX+n),reg8\n"); - } - ___output(ae,0xCB); - switch (GetCRC(ae->wl[ae->idx+3].w)) { - case CRC_B:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x0+o);ae->nop+=7;break; - case CRC_C:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x1+o);ae->nop+=7;break; - case CRC_D:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x2+o);ae->nop+=7;break; - case CRC_E:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x3+o);ae->nop+=7;break; - case CRC_H:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x4+o);ae->nop+=7;break; - case CRC_L:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x5+o);ae->nop+=7;break; - case CRC_A:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);PushExpression(ae,ae->idx+1,E_EXPRESSION_BRS);___output(ae,0x7+o);ae->nop+=7;break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SET n,(IX+n),reg8\n"); - } - ae->idx+=3; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SET n,reg8/(HL)/(IX+n)[,reg8]/(IY+n)[,reg8]\n"); - } - } -} - -void _DEFS(struct s_assenv *ae) { - int i,r,v; - if (ae->wl[ae->idx].t) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Syntax is DEFS repeat,value or DEFS repeat\n"); - } else do { - ae->idx++; - if (!ae->wl[ae->idx].t) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); /* doing FastTranslate but not a complete evaluation */ - r=RoundComputeExpressionCore(ae,ae->wl[ae->idx].w,ae->codeadr,0); - if (r<0) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFS size must be greater or equal to zero\n"); - } - for (i=0;iidx+1,E_EXPRESSION_0V8); - ae->nop+=1; - } - ae->idx++; - } else if (ae->wl[ae->idx].t==1) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); - r=RoundComputeExpressionCore(ae,ae->wl[ae->idx].w,ae->codeadr,0); - v=0; - if (r<0) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFS size must be greater or equal to zero\n"); - } - for (i=0;inop+=1; - } - } - } while (!ae->wl[ae->idx].t); -} - -void _DEFS_struct(struct s_assenv *ae) { - int i,r,v; - if (ae->wl[ae->idx].t) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Syntax is DEFS repeat,value or DEFS repeat\n"); - } else do { - ae->idx++; - if (!ae->wl[ae->idx].t) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - r=RoundComputeExpressionCore(ae,ae->wl[ae->idx].w,ae->codeadr,0); - v=RoundComputeExpressionCore(ae,ae->wl[ae->idx+1].w,ae->codeadr,0); - if (r<0) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFS size must be greater or equal to zero\n"); - } - for (i=0;inop+=1; - } - ae->idx++; - } else if (ae->wl[ae->idx].t==1) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); - r=RoundComputeExpressionCore(ae,ae->wl[ae->idx].w,ae->codeadr,0); - v=0; - if (r<0) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFS size must be greater or equal to zero\n"); - } - for (i=0;inop+=1; - } - } - } while (!ae->wl[ae->idx].t); -} - -void _STR(struct s_assenv *ae) { - unsigned char c; - int i,tquote; - - if (!ae->wl[ae->idx].t) { - do { - ae->idx++; - if ((tquote=StringIsQuote(ae->wl[ae->idx].w))!=0) { - i=1; - while (ae->wl[ae->idx].w[i] && ae->wl[ae->idx].w[i]!=tquote) { - if (ae->wl[ae->idx].w[i]=='\\') { - i++; - /* no conversion on escaped chars */ - c=ae->wl[ae->idx].w[i]; - switch (c) { - case 'b':c='\b';break; - case 'v':c='\v';break; - case 'f':c='\f';break; - case '0':c='\0';break; - case 'r':c='\r';break; - case 'n':c='\n';break; - case 't':c='\t';break; - default:break; - } - if (ae->wl[ae->idx].w[i+1]!=tquote) { - ___output(ae,c); - } else { - ___output(ae,c|0x80); - } - } else { - /* charset conversion on the fly */ - if (ae->wl[ae->idx].w[i+1]!=tquote) { - ___output(ae,ae->charset[(int)ae->wl[ae->idx].w[i]]); - } else { - ___output(ae,ae->charset[(int)ae->wl[ae->idx].w[i]]|0x80); - } - } - - i++; - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"STR handle only quoted strings!\n"); - } - } while (ae->wl[ae->idx].t==0); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"STR needs one or more quotes parameters\n"); - } -} - -void _DEFR(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t) { - do { - ae->idx++; - PushExpression(ae,ae->idx,E_EXPRESSION_0VR); - } while (ae->wl[ae->idx].t==0); - } else { - if (ae->getstruct) { - ___output(ae,0);___output(ae,0);___output(ae,0);___output(ae,0);___output(ae,0); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFR needs one or more parameters\n"); - } - } -} -void _DEFR_struct(struct s_assenv *ae) { - unsigned char *rc; - double v; - if (!ae->wl[ae->idx].t) { - do { - ae->idx++; - /* conversion des symboles connus */ - ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); - /* calcul de la valeur définitive de l'expression */ - v=ComputeExpressionCore(ae,ae->wl[ae->idx].w,ae->outputadr,0); - /* conversion en réel Amsdos */ - rc=__internal_MakeAmsdosREAL(ae,v,0); - ___output(ae,rc[0]);___output(ae,rc[1]);___output(ae,rc[2]);___output(ae,rc[3]);___output(ae,rc[4]); - } while (ae->wl[ae->idx].t==0); - } else { - if (ae->getstruct) { - ___output(ae,0);___output(ae,0);___output(ae,0);___output(ae,0);___output(ae,0); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFR needs one or more parameters\n"); - } - } -} - -void _DEFB(struct s_assenv *ae) { - int i,tquote; - unsigned char c; - if (!ae->wl[ae->idx].t) { - do { - ae->idx++; - if ((tquote=StringIsQuote(ae->wl[ae->idx].w))!=0) { - i=1; - while (ae->wl[ae->idx].w[i] && ae->wl[ae->idx].w[i]!=tquote) { - if (ae->wl[ae->idx].w[i]=='\\') { - i++; - /* no conversion on escaped chars */ - c=ae->wl[ae->idx].w[i]; - switch (c) { - case 'b':___output(ae,'\b');break; - case 'v':___output(ae,'\v');break; - case 'f':___output(ae,'\f');break; - case '0':___output(ae,'\0');break; - case 'r':___output(ae,'\r');break; - case 'n':___output(ae,'\n');break; - case 't':___output(ae,'\t');break; - default: - ___output(ae,c); - ae->nop+=1; - } - } else { - /* charset conversion on the fly */ - ___output(ae,ae->charset[(int)ae->wl[ae->idx].w[i]]); - ae->nop+=1; - } - i++; - } - } else { - PushExpression(ae,ae->idx,E_EXPRESSION_0V8); - ae->nop+=1; - } - } while (ae->wl[ae->idx].t==0); - } else { - if (ae->getstruct) { - ___output(ae,0); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFB needs one or more parameters\n"); - } - } -} -void _DEFB_struct(struct s_assenv *ae) { - int i,tquote; - unsigned char c; - if (!ae->wl[ae->idx].t) { - do { - ae->idx++; - if ((tquote=StringIsQuote(ae->wl[ae->idx].w))!=0) { - i=1; - while (ae->wl[ae->idx].w[i] && ae->wl[ae->idx].w[i]!=tquote) { - if (ae->wl[ae->idx].w[i]=='\\') { - i++; - /* no conversion on escaped chars */ - c=ae->wl[ae->idx].w[i]; - switch (c) { - case 'b':___output(ae,'\b');break; - case 'v':___output(ae,'\v');break; - case 'f':___output(ae,'\f');break; - case '0':___output(ae,'\0');break; - case 'r':___output(ae,'\r');break; - case 'n':___output(ae,'\n');break; - case 't':___output(ae,'\t');break; - default: - ___output(ae,c); - ae->nop+=1; - } - } else { - /* charset conversion on the fly */ - ___output(ae,ae->charset[(int)ae->wl[ae->idx].w[i]]); - ae->nop+=1; - } - i++; - } - } else { - int v; - ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); - v=RoundComputeExpressionCore(ae,ae->wl[ae->idx].w,ae->outputadr,0); - ___output(ae,v); - ae->nop+=1; - } - } while (ae->wl[ae->idx].t==0); - } else { - if (ae->getstruct) { - ___output(ae,0); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFB needs one or more parameters\n"); - } - } -} - -void _DEFW(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t) { - do { - ae->idx++; - PushExpression(ae,ae->idx,E_EXPRESSION_0V16); - } while (ae->wl[ae->idx].t==0); - } else { - if (ae->getstruct) { - ___output(ae,0);___output(ae,0); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFW needs one or more parameters\n"); - } - } -} - -void _DEFW_struct(struct s_assenv *ae) { - int v; - if (!ae->wl[ae->idx].t) { - do { - ae->idx++; - ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); - v=RoundComputeExpressionCore(ae,ae->wl[ae->idx].w,ae->outputadr,0); - ___output(ae,v&0xFF);___output(ae,(v>>8)&0xFF); - } while (ae->wl[ae->idx].t==0); - } else { - if (ae->getstruct) { - ___output(ae,0);___output(ae,0); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFW needs one or more parameters\n"); - } - } -} - -void _DEFI(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t) { - do { - ae->idx++; - PushExpression(ae,ae->idx,E_EXPRESSION_0V32); - } while (ae->wl[ae->idx].t==0); - } else { - if (ae->getstruct) { - ___output(ae,0);___output(ae,0);___output(ae,0);___output(ae,0); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFI needs one or more parameters\n"); - } - } -} - -void _DEFI_struct(struct s_assenv *ae) { - int v; - if (!ae->wl[ae->idx].t) { - do { - ae->idx++; - ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); - v=RoundComputeExpressionCore(ae,ae->wl[ae->idx].w,ae->outputadr,0); - ___output(ae,v&0xFF);___output(ae,(v>>8)&0xFF);___output(ae,(v>>16)&0xFF);___output(ae,(v>>24)&0xFF); - } while (ae->wl[ae->idx].t==0); - } else { - if (ae->getstruct) { - ___output(ae,0);___output(ae,0);___output(ae,0);___output(ae,0); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFI needs one or more parameters\n"); - } - } -} - -void _DEFB_as80(struct s_assenv *ae) { - int i,tquote; - int modadr=0; - - if (!ae->wl[ae->idx].t) { - do { - ae->idx++; - if ((tquote=StringIsQuote(ae->wl[ae->idx].w))!=0) { - i=1; - while (ae->wl[ae->idx].w[i] && ae->wl[ae->idx].w[i]!=tquote) { - if (ae->wl[ae->idx].w[i]=='\\') i++; - /* charset conversion on the fly */ - ___output(ae,ae->charset[(int)ae->wl[ae->idx].w[i]]); - ae->nop+=1; - ae->codeadr--;modadr++; - i++; - } - } else { - PushExpression(ae,ae->idx,E_EXPRESSION_0V8); - ae->codeadr--;modadr++; - ae->nop+=1; - } - } while (ae->wl[ae->idx].t==0); - ae->codeadr+=modadr; - } else { - if (ae->getstruct) { - ___output(ae,0); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFB needs one or more parameters\n"); - } - } -} - -void _DEFW_as80(struct s_assenv *ae) { - int modadr=0; - if (!ae->wl[ae->idx].t) { - do { - ae->idx++; - PushExpression(ae,ae->idx,E_EXPRESSION_0V16); - ae->codeadr-=2;modadr+=2; - } while (ae->wl[ae->idx].t==0); - ae->codeadr+=modadr; - } else { - if (ae->getstruct) { - ___output(ae,0);___output(ae,0); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFW needs one or more parameters\n"); - } - } -} - -void _DEFI_as80(struct s_assenv *ae) { - int modadr=0; - if (!ae->wl[ae->idx].t) { - do { - ae->idx++; - PushExpression(ae,ae->idx,E_EXPRESSION_0V32); - ae->codeadr-=4;modadr+=4; - } while (ae->wl[ae->idx].t==0); - ae->codeadr+=modadr; - } else { - if (ae->getstruct) { - ___output(ae,0);___output(ae,0);___output(ae,0);___output(ae,0); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFI needs one or more parameters\n"); - } - } -} -#if 0 -void _DEFSTR(struct s_assenv *ae) { - int i,tquote; - unsigned char c; - if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { - if (StringIsQuote(ae->wl[ae->idx+1].w) && StringIsQuote(ae->wl[ae->idx+2].w)) { - i=1; - while (ae->wl[ae->idx].w[i] && ae->wl[ae->idx].w[i]!=tquote) { - if (ae->wl[ae->idx].w[i]=='\\') { - i++; - /* no conversion on escaped chars */ - c=ae->wl[ae->idx].w[i]; - switch (c) { - case 'b':___output(ae,'\b');break; - case 'v':___output(ae,'\v');break; - case 'f':___output(ae,'\f');break; - case '0':___output(ae,'\0');break; - case 'r':___output(ae,'\r');break; - case 'n':___output(ae,'\n');break; - case 't':___output(ae,'\t');break; - default: - ___output(ae,c); - } - } else { - /* charset conversion on the fly */ - ___output(ae,ae->charset[(int)ae->wl[ae->idx].w[i]]); - } - i++; - } - } - ae->idx+=2; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFSTR needs two parameters\n"); - } -} -#endif - -#undef FUNC -#define FUNC "Directive CORE" - -void __internal_UpdateLZBlockIfAny(struct s_assenv *ae) { - /* there was a crunched block opened in the previous bank */ - if (ae->lz>=0) { - //ae->lzsection[ae->ilz-1].iorgzone=ae->io-1; - //ae->lzsection[ae->ilz-1].ibank=ae->activebank; - } - ae->lz=-1; -} - - -void __AMSDOS(struct s_assenv *ae) { - ae->amsdos=1; -} - -void __internal_EXPORT(struct s_assenv *ae, int exportval) { - struct s_label *curlabel; - struct s_expr_dico *curdic; - int ialias,crc,freeflag; - char *localname; - - if (ae->wl[ae->idx].t) { - /* without parameter enable/disable export */ - ae->autorise_export=exportval; - } else while (!ae->wl[ae->idx].t) { - ae->idx++; - freeflag=0; - - /* local label */ - if (ae->wl[ae->idx].w[0]=='.' && ae->lastgloballabel) { - localname=MemMalloc(strlen(ae->wl[ae->idx].w)+1+ae->lastgloballabellen); - sprintf(localname,"%s%s",ae->lastgloballabel,ae->wl[ae->idx].w); - freeflag=1; - } else { - localname=ae->wl[ae->idx].w; - } - crc=GetCRC(localname); - - if ((curlabel=SearchLabel(ae,localname,crc))!=NULL) { - curlabel->autorise_export=exportval; - ae->label[curlabel->backidx].autorise_export=exportval; - } else { - if ((curdic=SearchDico(ae,ae->wl[ae->idx].w,crc))!=NULL) { - curdic->autorise_export=exportval; - } else { - if ((ialias=SearchAlias(ae,crc,ae->wl[ae->idx].w))!=-1) { - ae->alias[ialias].autorise_export=exportval; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"(E)NOEXPORT did not found [%s] in variables, labels or aliases\n",ae->wl[ae->idx].w); - } - } - } - if (freeflag) MemFree(localname); - } -} -void __NOEXPORT(struct s_assenv *ae) { - __internal_EXPORT(ae,0); -} -void __ENOEXPORT(struct s_assenv *ae) { - __internal_EXPORT(ae,1); -} - -void __BUILDZX(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BUILDZX does not need a parameter\n"); - } - if (!ae->forcesnapshot && !ae->forcetape && !ae->forcecpr) { - ae->forcezx=1; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot select ZX output when already in Amstrad cartridge/snapshot/tape output\n"); - } -} -void __BUILDCPR(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BUILDCPR does not need a parameter\n"); - } - if (!ae->forcesnapshot && !ae->forcetape && !ae->forcezx) { - ae->forcecpr=1; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot select Amstrad cartridge output when already in snapshot/tape output\n"); - } -} -void __BUILDSNA(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t) { - if (strcmp(ae->wl[ae->idx+1].w,"V2")==0) { - ae->snapshot.version=2; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BUILDSNA unrecognized option\n"); - } - } - if (!ae->forcecpr && !ae->forcetape && !ae->forcezx) { - ae->forcesnapshot=1; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot select snapshot output when already in cartridge/tape output\n"); - } -} -void __BUILDROM(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BUILDROM does not need a parameter\n"); - } - if (!ae->forcesnapshot && !ae->forcetape && !ae->forcezx && !ae->forcecpr) { - ae->forceROM=1; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot select Amstrad ROM output when already in snapshot/tape/zx/cartridge output\n"); - } -} -void __BUILDTAPE(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BUILDTAPE does not need a parameter\n"); - } - if (!ae->forcesnapshot && !ae->forcecpr && !ae->forcezx) { - ae->forcetape=1; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot select tape output when already in snapshot/cartridge output\n"); - } -} - - -void __LZ4(struct s_assenv *ae) { - struct s_lz_section curlz; - - if (!ae->wl[ae->idx].t) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LZ directive does not need any parameter\n"); - return; - } - #ifdef NO_3RD_PARTIES - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use 3rd parties cruncher with this version of RASM\n",GetCurrentFile(ae),ae->wl[ae->idx].l); - FreeAssenv(ae); - exit(-5); - #endif - - if (ae->lz>=0 && ae->lzilz) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot start a new LZ section inside another one (%d)\n",GetCurrentFile(ae),ae->wl[ae->idx].l,ae->lz); - FreeAssenv(ae); - exit(-5); - } - curlz.iw=ae->idx; - curlz.iorgzone=ae->io-1; - curlz.ibank=ae->activebank; - curlz.memstart=ae->outputadr; - curlz.memend=-1; - curlz.lzversion=4; - ae->lz=ae->ilz; - ObjectArrayAddDynamicValueConcat((void**)&ae->lzsection,&ae->ilz,&ae->mlz,&curlz,sizeof(curlz)); -} -void __LZX7(struct s_assenv *ae) { - struct s_lz_section curlz; - - if (!ae->wl[ae->idx].t) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LZ directive does not need any parameter\n"); - return; - } - #ifdef NO_3RD_PARTIES - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use 3rd parties cruncher with this version of RASM\n",GetCurrentFile(ae),ae->wl[ae->idx].l); - FreeAssenv(ae); - exit(-5); - #endif - - if (ae->lz>=0 && ae->lzilz) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot start a new LZ section inside another one (%d)\n",GetCurrentFile(ae),ae->wl[ae->idx].l,ae->lz); - FreeAssenv(ae); - exit(-5); - } - curlz.iw=ae->idx; - curlz.iorgzone=ae->io-1; - curlz.ibank=ae->activebank; - curlz.memstart=ae->outputadr; - curlz.memend=-1; - curlz.lzversion=7; - ae->lz=ae->ilz; - ObjectArrayAddDynamicValueConcat((void**)&ae->lzsection,&ae->ilz,&ae->mlz,&curlz,sizeof(curlz)); -} -void __LZEXO(struct s_assenv *ae) { - struct s_lz_section curlz; - - if (!ae->wl[ae->idx].t) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LZ directive does not need any parameter\n"); - return; - } - #ifdef NO_3RD_PARTIES - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use 3rd parties cruncher with this version of RASM\n",GetCurrentFile(ae),ae->wl[ae->idx].l); - FreeAssenv(ae); - exit(-5); - #endif - - if (ae->lz>=0 && ae->lzilz) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot start a new LZ section inside another one (%d)\n",GetCurrentFile(ae),ae->wl[ae->idx].l,ae->lz); - FreeAssenv(ae); - exit(-5); - } - curlz.iw=ae->idx; - curlz.iorgzone=ae->io-1; - curlz.ibank=ae->activebank; - curlz.memstart=ae->outputadr; - curlz.memend=-1; - curlz.lzversion=8; - ae->lz=ae->ilz; - ObjectArrayAddDynamicValueConcat((void**)&ae->lzsection,&ae->ilz,&ae->mlz,&curlz,sizeof(curlz)); -} -void __LZ48(struct s_assenv *ae) { - struct s_lz_section curlz; - - if (!ae->wl[ae->idx].t) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LZ directive does not need any parameter\n"); - return; - } - if (ae->lz>=0 && ae->lzilz) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot start a new LZ section inside another one (%d)\n",GetCurrentFile(ae),ae->wl[ae->idx].l,ae->lz); - FreeAssenv(ae); - exit(-5); - } - curlz.iw=ae->idx; - curlz.iorgzone=ae->io-1; - curlz.ibank=ae->activebank; - curlz.memstart=ae->outputadr; - curlz.memend=-1; - curlz.lzversion=48; - ae->lz=ae->ilz; - ObjectArrayAddDynamicValueConcat((void**)&ae->lzsection,&ae->ilz,&ae->mlz,&curlz,sizeof(curlz)); -} -void __LZ49(struct s_assenv *ae) { - struct s_lz_section curlz; - - if (!ae->wl[ae->idx].t) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LZ directive does not need any parameter\n"); - return; - } - if (ae->lz>=0 && ae->lzilz) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot start a new LZ section inside another one (%d)\n",GetCurrentFile(ae),ae->wl[ae->idx].l,ae->lz); - FreeAssenv(ae); - exit(-5); - } - - curlz.iw=ae->idx; - curlz.iorgzone=ae->io-1; - curlz.ibank=ae->activebank; - curlz.memstart=ae->outputadr; - curlz.memend=-1; - curlz.lzversion=49; - ae->lz=ae->ilz; - ObjectArrayAddDynamicValueConcat((void**)&ae->lzsection,&ae->ilz,&ae->mlz,&curlz,sizeof(curlz)); -} -void __LZCLOSE(struct s_assenv *ae) { - if (!ae->ilz || ae->lz==-1) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot close LZ section as it wasn't opened\n"); - return; - } - - ae->lzsection[ae->ilz-1].memend=ae->outputadr; - ae->lzsection[ae->ilz-1].ilabel=ae->il; - ae->lzsection[ae->ilz-1].iexpr=ae->ie; - //ae->lz=ae->ilz; - ae->lz=-1; -} - -void __LIMIT(struct s_assenv *ae) { - if (ae->wl[ae->idx+1].t!=2) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - ___output_set_limit(ae,RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->outputadr,0,0)); - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LIMIT directive need one integer parameter\n"); - } -} -void OverWriteCheck(struct s_assenv *ae) -{ - #undef FUNC - #define FUNC "OverWriteCheck" - - int i,j; - - /* overwrite checking */ - i=ae->io-1; { - if (ae->orgzone[i].memstart!=ae->orgzone[i].memend) { - for (j=0;jio-1;j++) { - if (ae->orgzone[j].memstart!=ae->orgzone[j].memend && !ae->orgzone[j].nocode) { - if (ae->orgzone[i].ibank==ae->orgzone[j].ibank) { - if ((ae->orgzone[i].memstart>=ae->orgzone[j].memstart && ae->orgzone[i].memstartorgzone[j].memend) - || (ae->orgzone[i].memend>ae->orgzone[j].memstart && ae->orgzone[i].memendorgzone[j].memend) - || (ae->orgzone[i].memstart<=ae->orgzone[j].memstart && ae->orgzone[i].memend>=ae->orgzone[j].memend)) { - ae->idx--; - if (ae->orgzone[j].protect) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"PROTECTED section error [%s] L%d [#%04X-#%04X-B%d] with [%s] L%d [#%04X/#%04X]\n",ae->filename[ae->orgzone[j].ifile],ae->orgzone[j].iline,ae->orgzone[j].memstart,ae->orgzone[j].memend,ae->orgzone[j].ibank<32?ae->orgzone[j].ibank:0,ae->filename[ae->orgzone[i].ifile],ae->orgzone[i].iline,ae->orgzone[i].memstart,ae->orgzone[i].memend); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Assembling overwrite [%s] L%d [#%04X-#%04X-B%d] with [%s] L%d [#%04X/#%04X]\n",ae->filename[ae->orgzone[j].ifile],ae->orgzone[j].iline,ae->orgzone[j].memstart,ae->orgzone[j].memend,ae->orgzone[j].ibank<32?ae->orgzone[j].ibank:0,ae->filename[ae->orgzone[i].ifile],ae->orgzone[i].iline,ae->orgzone[i].memstart,ae->orgzone[i].memend); - } - i=j=ae->io; - break; - } - } - } - } - } - } -} - -void ___new_memory_space(struct s_assenv *ae) -{ - #undef FUNC - #define FUNC "___new_memory_space" - - unsigned char *mem; - struct s_orgzone orgzone={0}; - - __internal_UpdateLZBlockIfAny(ae); - if (ae->io) { - ae->orgzone[ae->io-1].memend=ae->outputadr; - } - if (ae->lz>=0) { - if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: LZ section wasn't closed before a new memory space directive\n",GetCurrentFile(ae),ae->wl[ae->idx].l); - __LZCLOSE(ae); - } - ae->activebank=ae->nbbank; - mem=MemMalloc(65536); - memset(mem,0,65536); - ObjectArrayAddDynamicValueConcat((void**)&ae->mem,&ae->nbbank,&ae->maxbank,&mem,sizeof(mem)); - - ae->outputadr=0; - ae->codeadr=0; - orgzone.memstart=0; - orgzone.ibank=ae->activebank; - orgzone.nocode=ae->nocode=0; - ObjectArrayAddDynamicValueConcat((void**)&ae->orgzone,&ae->io,&ae->mo,&orgzone,sizeof(orgzone)); - - OverWriteCheck(ae); -} - -void __BANK(struct s_assenv *ae) { - struct s_orgzone orgzone={0}; - int oldcode=0,oldoutput=0; - int i; - __internal_UpdateLZBlockIfAny(ae); - - if (ae->io) { - ae->orgzone[ae->io-1].memend=ae->outputadr; - } - /* without parameter, create a new empty space */ - if (ae->wl[ae->idx].t==1) { - ___new_memory_space(ae); - return; - } - - ae->bankmode=1; - if (!ae->forceROM && !ae->forcecpr && !ae->forcesnapshot && !ae->forcezx) ae->forcecpr=1; - - if (ae->wl[ae->idx+1].t!=2) { - if (strcmp(ae->wl[ae->idx+1].w,"NEXT")==0) { - /* are we in a temporary space or in the very last bank? */ - if (ae->activebank>=260-1) { - ___new_memory_space(ae); - return; - } - /* switch to next bank! */ - ae->activebank++; - } else { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - ae->activebank=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); - } - if (ae->forcecpr && (ae->activebank<0 || ae->activebank>31)) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"FATAL - Bank selection must be from 0 to 31 in cartridge mode\n",GetCurrentFile(ae),ae->wl[ae->idx].l); - FreeAssenv(ae); - exit(2); - } else if (ae->forcezx && (ae->activebank<0 || ae->activebank>7)) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"FATAL - Bank selection must be from 0 to 7 in ZX Spectrum mode\n",GetCurrentFile(ae),ae->wl[ae->idx].l); - FreeAssenv(ae); - exit(2); - } else if (ae->forceROM && (ae->activebank<0 || ae->activebank>=256)) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"FATAL - Bank selection must be from 0 to 255 in ROM mode\n",GetCurrentFile(ae),ae->wl[ae->idx].l); - FreeAssenv(ae); - exit(2); - } else if (ae->forcesnapshot && (ae->activebank<0 || ae->activebank>=260)) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"FATAL - Bank selection must be from 0 to 259 in snapshot mode\n",GetCurrentFile(ae),ae->wl[ae->idx].l); - FreeAssenv(ae); - exit(2); - } - /* bankset control */ - if (ae->forcesnapshot && ae->bankset[ae->activebank/4]) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot BANK %d was already select by a previous BANKSET %d\n",ae->activebank,(int)ae->activebank/4); - ae->idx++; - return; - } else { - ae->bankused[ae->activebank]=1; - } - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BANK directive need one integer parameter\n"); - return; - } - if (ae->lz>=0) { - if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: LZ section wasn't closed before a new BANK directive\n",GetCurrentFile(ae),ae->wl[ae->idx].l); - __LZCLOSE(ae); - } - - /* try to get an old ORG settings backward */ - for (i=ae->io-1;i>=0;i--) { - if (ae->orgzone[i].ibank==ae->activebank) { - oldcode=ae->orgzone[i].memend; - oldoutput=ae->orgzone[i].memend; - break; - } - } - ae->outputadr=oldoutput; - ae->codeadr=oldcode; - orgzone.memstart=ae->outputadr; - /* legacy */ - orgzone.ibank=ae->activebank; - orgzone.nocode=ae->nocode=0; - ObjectArrayAddDynamicValueConcat((void**)&ae->orgzone,&ae->io,&ae->mo,&orgzone,sizeof(orgzone)); - - OverWriteCheck(ae); -} - -void __BANKSET(struct s_assenv *ae) { - struct s_orgzone orgzone={0}; - int ibank; - - __internal_UpdateLZBlockIfAny(ae); - - if (!ae->forcesnapshot && !ae->forcecpr && !ae->forcezx) ae->forcesnapshot=1; - if (!ae->forcesnapshot) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BANKSET directive is specific to snapshot output\n"); - return; - } - - if (ae->io) { - ae->orgzone[ae->io-1].memend=ae->outputadr; - } - ae->bankmode=1; - - if (ae->wl[ae->idx+1].t!=2) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - ae->activebank=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); - ae->activebank*=4; - if (ae->forcesnapshot && (ae->activebank<0 || ae->activebank>=260)) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"FATAL - Bank set selection must be from 0 to 64 in snapshot mode\n",GetCurrentFile(ae),ae->wl[ae->idx].l); - FreeAssenv(ae); - exit(2); - } - /* control */ - ibank=ae->activebank; - if (ae->bankused[ibank] || ae->bankused[ibank+1]|| ae->bankused[ibank+2]|| ae->bankused[ibank+3]) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot BANKSET because bank %d was already selected in single page mode\n",ibank); - ae->idx++; - return; - } else { - ae->bankset[ae->activebank/4]=1; /* pas très heureux mais bon... */ - } - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BANKSET directive need one integer parameter\n"); - return; - } - if (ae->lz>=0) { - if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: LZ section wasn't closed before a new BANKSET directive\n",GetCurrentFile(ae),ae->wl[ae->idx].l); - __LZCLOSE(ae); - } - - ae->outputadr=0; - ae->codeadr=0; - orgzone.memstart=0; - orgzone.ibank=ae->activebank; - orgzone.nocode=ae->nocode=0; - ObjectArrayAddDynamicValueConcat((void**)&ae->orgzone,&ae->io,&ae->mo,&orgzone,sizeof(orgzone)); - - OverWriteCheck(ae); -} - - -void __NameBANK(struct s_assenv *ae) { - int ibank; - - ae->bankmode=1; - if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { - if (!StringIsQuote(ae->wl[ae->idx+2].w)) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Syntax is NAMEBANK ,''\n"); - } else { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - ibank=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); - if (ibank<0 || ibank>=BANK_MAX_NUMBER) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"NAMEBANK selection must be from 0 to %d\n",BANK_MAX_NUMBER); - } else { - ae->iwnamebank[ibank]=ae->idx+2; - } - } - ae->idx+=2; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"NAMEBANK directive need one integer parameter and a string\n"); - } -} - -/*** - Winape little compatibility for CPR writing! -*/ -void __WRITE(struct s_assenv *ae) { - int ok=0; - int lower=-1,upper=-1,bank=-1; - - if (!ae->wl[ae->idx].t && strcmp(ae->wl[ae->idx+1].w,"DIRECT")==0 && !ae->wl[ae->idx+1].t) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+2].w,0); - lower=RoundComputeExpression(ae,ae->wl[ae->idx+2].w,ae->codeadr,0,0); - if (!ae->wl[ae->idx+2].t) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+3].w,0); - upper=RoundComputeExpression(ae,ae->wl[ae->idx+3].w,ae->codeadr,0,0); - } - if (!ae->wl[ae->idx+3].t) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+4].w,0); - bank=RoundComputeExpression(ae,ae->wl[ae->idx+4].w,ae->codeadr,0,0); - } - - if (ae->maxam) { - if (lower==65535) lower=-1; - if (upper==65535) upper=-1; - if (bank==65535) bank=-1; - } - - if (lower!=-1) { - if (lower>=0 && lower<8) { - ae->idx+=1; - __BANK(ae); - ok=1; - } else { - if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: WRITE DIRECT lower ROM ignored (value %d out of bounds 0-7)\n",GetCurrentFile(ae),ae->wl[ae->idx].l,lower); - } - } else if (upper!=-1) { - if (upper>=0 && ((ae->forcecpr && upper<32) || (ae->forcesnapshot && upperidx+=2; - __BANK(ae); - ok=1; - } else { - if (!ae->forcecpr && !ae->forcesnapshot) { - if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: WRITE DIRECT select a ROM without cartridge output\n",GetCurrentFile(ae),ae->wl[ae->idx].l); - } else { - if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: WRITE DIRECT upper ROM ignored (value %d out of bounds 0-31)\n",GetCurrentFile(ae),ae->wl[ae->idx].l,upper); - } - } - } else if (bank!=-1) { - /* selection de bank on ouvre un nouvel espace */ - } else { - if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: meaningless WRITE DIRECT\n",GetCurrentFile(ae),ae->wl[ae->idx].l); - } - } - while (!ae->wl[ae->idx].t) ae->idx++; - if (!ok) { - ___new_memory_space(ae); - } -} -void __CHARSET(struct s_assenv *ae) { - int i,s,e,v,tquote; - - if (ae->wl[ae->idx].t==1) { - /* reinit charset */ - for (i=0;i<256;i++) - ae->charset[i]=i; - } else if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { - /* string,value | byte,value */ - ExpressionFastTranslate(ae,&ae->wl[ae->idx+2].w,0); - v=RoundComputeExpression(ae,ae->wl[ae->idx+2].w,ae->codeadr,0,0); - if (ae->wl[ae->idx+1].w[0]=='\'' || ae->wl[ae->idx+1].w[0]=='"') { - tquote=ae->wl[ae->idx+1].w[0]; - if (ae->wl[ae->idx+1].w[strlen(ae->wl[ae->idx+1].w)-1]==tquote) { - i=1; - while (ae->wl[ae->idx+1].w[i] && ae->wl[ae->idx+1].w[i]!=tquote) { - if (ae->wl[ae->idx+1].w[i]=='\\') i++; - ae->charset[(int)ae->wl[ae->idx+1].w[i]]=(unsigned char)v++; - i++; - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CHARSET string,value has invalid quote!\n"); - } - } else { - i=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); - if (i>=0 && i<256) { - ae->charset[i]=(unsigned char)v; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CHARSET byte value must be 0-255\n"); - } - } - ae->idx+=2; - } else if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && !ae->wl[ae->idx+2].t && ae->wl[ae->idx+3].t==1) { - /* start,end,value */ - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - ExpressionFastTranslate(ae,&ae->wl[ae->idx+2].w,0); - ExpressionFastTranslate(ae,&ae->wl[ae->idx+3].w,0); - s=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); - e=RoundComputeExpression(ae,ae->wl[ae->idx+2].w,ae->codeadr,0,0); - v=RoundComputeExpression(ae,ae->wl[ae->idx+3].w,ae->codeadr,0,0); - ae->idx+=3; - if (s<=e && s>=0 && e<256) { - for (i=s;i<=e;i++) { - ae->charset[i]=(unsigned char)v++; - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CHARSET winape directive wrong interval value\n"); - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CHARSET winape directive wrong parameter count\n"); - } -} - -void __MACRO(struct s_assenv *ae) { - struct s_macro curmacro={0}; - char *referentfilename,*zeparam; - int refidx,idx,getparam=1; - struct s_wordlist curwl; - - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t!=2) { - /* get the name */ - curmacro.mnemo=ae->wl[ae->idx+1].w; - curmacro.crc=GetCRC(curmacro.mnemo); - if (ae->wl[ae->idx+1].t) { - getparam=0; - } - /* overload forbidden */ - if (SearchMacro(ae,curmacro.crc,curmacro.mnemo)>=0) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Macro already defined with this name\n"); - } - idx=ae->idx+2; - while (ae->wl[idx].t!=2 && (GetCRC(ae->wl[idx].w)!=CRC_MEND || strcmp(ae->wl[idx].w,"MEND")!=0) && (GetCRC(ae->wl[idx].w)!=CRC_ENDM || strcmp(ae->wl[idx].w,"ENDM")!=0)) { - if (GetCRC(ae->wl[idx].w)==CRC_MACRO || strcmp(ae->wl[idx].w,"MACRO")==0) { - /* inception interdite */ - referentfilename=GetCurrentFile(ae); - refidx=ae->idx; - ae->idx=idx; - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"You cannot define a macro inside another one (MACRO %s in [%s] L%d)\n",ae->wl[refidx+1].w,referentfilename,ae->wl[refidx].l); - __STOP(ae); - } - if (getparam) { - /* on prepare les parametres au remplacement */ - zeparam=MemMalloc(strlen(ae->wl[idx].w)+3); - if (ae->as80) { - sprintf(zeparam,"%s",ae->wl[idx].w); - } else { - sprintf(zeparam,"{%s}",ae->wl[idx].w); - } - curmacro.nbparam++; - curmacro.param=MemRealloc(curmacro.param,curmacro.nbparam*sizeof(char **)); - curmacro.param[curmacro.nbparam-1]=zeparam; - if (ae->wl[idx].t) { - /* duplicate parameters without brackets MUST be an OPTION */ - getparam=0; - } - } else { - /* copie la liste de mots */ - curwl=ae->wl[idx]; - ObjectArrayAddDynamicValueConcat((void **)&curmacro.wc,&curmacro.nbword,&curmacro.maxword,&curwl,sizeof(struct s_wordlist)); - } - idx++; - } - if (ae->wl[idx].t==2) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Macro was not closed\n"); - } - ObjectArrayAddDynamicValueConcat((void**)&ae->macro,&ae->imacro,&ae->mmacro,&curmacro,sizeof(curmacro)); - /* le quicksort n'est pas optimal mais on n'est pas supposé en créer des milliers */ - qsort(ae->macro,ae->imacro,sizeof(struct s_macro),cmpmacros); - - /* ajustement des mots lus */ - if (ae->wl[idx].t==2) idx--; - ae->idx=idx; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"MACRO definition need at least one parameter\n"); - } -} - -struct s_wordlist *__MACRO_EXECUTE(struct s_assenv *ae, int imacro) { - struct s_wordlist *cpybackup; - int nbparam=0,idx,i,j,idad; - int ifile,iline,iu,lenparam; - double v; - struct s_macro_position curmacropos={0}; - char *zeparam=NULL,*txtparamlist; - int reload=0; - - idx=ae->idx; - while (!ae->wl[idx].t) { - nbparam++; - idx++; - } - - /* hack to secure macro without parameters with void argument */ - if (!ae->macro[imacro].nbparam) { - if (nbparam) { - if (nbparam==1 && strcmp(ae->wl[ae->idx+1].w,"(VOID)")==0) { - nbparam=0; - reload=1; - } - } else { - if (ae->macrovoid) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"MACRO [%s] used without (void) and option -void used!\n",ae->macro[imacro].mnemo); - while (!ae->wl[ae->idx].t) { - ae->idx++; - } - ae->idx++; - } - } - } - /* macro must avoid extra params! */ - - /* cannot VOID a macro with parameters! */ - if (ae->macro[imacro].nbparam && strcmp(ae->wl[ae->idx+1].w,"(VOID)")==0) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"MACRO [%s] has %d parameter%s\n",ae->macro[imacro].mnemo,ae->macro[imacro].nbparam,ae->macro[imacro].nbparam>1?"s":""); - while (!ae->wl[ae->idx].t) { - ae->idx++; - } - ae->idx++; - } else { - if (nbparam!=ae->macro[imacro].nbparam) { - lenparam=1; // macro without parameters! - for (i=0;imacro[imacro].nbparam;i++) { - lenparam+=strlen(ae->macro[imacro].param[i])+3; - } - txtparamlist=MemMalloc(lenparam); - txtparamlist[0]=0; - for (i=0;imacro[imacro].nbparam;i++) { - strcat(txtparamlist,ae->macro[imacro].param[i]); - strcat(txtparamlist," "); - } - - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"MACRO [%s] was defined with %d parameter%s %s\n",ae->macro[imacro].mnemo,ae->macro[imacro].nbparam,ae->macro[imacro].nbparam>1?"s":"",txtparamlist); - while (!ae->wl[ae->idx].t) { - ae->idx++; - } - ae->idx++; - } else { - /* free macro call as we will overwrite it */ - MemFree(ae->wl[ae->idx].w); - /* is there a void to free? */ - if (reload) { - MemFree(ae->wl[ae->idx+1].w); - } - /* eval parameters? */ - for (i=0;iwl[ae->idx+1+i].w,"{EVAL}",6)==0) { - /* parametre entre chevrons, il faut l'interpreter d'abord */ - zeparam=TxtStrDup(ae->wl[ae->idx+1+i].w+6); - ExpressionFastTranslate(ae,&zeparam,1); - v=ComputeExpressionCore(ae,zeparam,ae->codeadr,0); - MemFree(zeparam); - zeparam=MemMalloc(32); - snprintf(zeparam,31,"%lf",v); - zeparam[31]=0; - MemFree(ae->wl[ae->idx+1+i].w); - ae->wl[ae->idx+1+i].w=zeparam; - } - } - /* backup parameters */ - cpybackup=MemMalloc((nbparam+1)*sizeof(struct s_wordlist)); - for (i=0;iwl[ae->idx+1+i]; - } - /* insert macro position */ - curmacropos.start=ae->idx; - curmacropos.end=ae->idx+ae->macro[imacro].nbword; - curmacropos.value=ae->macrocounter; - ObjectArrayAddDynamicValueConcat((void**)&ae->macropos,&ae->imacropos,&ae->mmacropos,&curmacropos,sizeof(curmacropos)); - - /* are we in a repeat/while block? */ - for (iu=0;iuir;iu++) if (ae->repeat[iu].maximimacropos) ae->repeat[iu].maxim=ae->imacropos; - for (iu=0;iuiw;iu++) if (ae->whilewend[iu].maximimacropos) ae->whilewend[iu].maxim=ae->imacropos; - - /* update daddy macropos */ - for (idad=0;idadimacropos-1;idad++) { - if (ae->macropos[idad].end>curmacropos.start) { - ae->macropos[idad].end+=ae->macro[imacro].nbword-1-nbparam-reload; /* coz la macro compte un mot! */ - } - } - - #if 0 - for (idad=0;idadimacropos;idad++) { - printf("macropos[%d]=%d -> %d\n",idad,ae->macropos[idad].start,ae->macropos[idad].end); - } - #endif - /* insert at macro position and replace macro+parameters */ - if (ae->macro[imacro].nbword>1+nbparam+reload) { - ae->nbword+=ae->macro[imacro].nbword-1-nbparam-reload; - ae->wl=MemRealloc(ae->wl,ae->nbword*sizeof(struct s_wordlist)); - } else { - /* si on réduit pas de realloc pour ne pas perdre de donnees */ - ae->nbword+=ae->macro[imacro].nbword-1-nbparam-reload; - } - iline=ae->wl[ae->idx].l; - ifile=ae->wl[ae->idx].ifile; - MemMove(&ae->wl[ae->idx+ae->macro[imacro].nbword],&ae->wl[ae->idx+reload+nbparam+1],(ae->nbword-ae->idx-ae->macro[imacro].nbword)*sizeof(struct s_wordlist)); - - for (i=0;imacro[imacro].nbword;i++) { - ae->wl[i+ae->idx].w=TxtStrDup(ae->macro[imacro].wc[i].w); - ae->wl[i+ae->idx].l=iline; - ae->wl[i+ae->idx].ifile=ifile; - /* @@@sujet a evolution, ou double controle */ - ae->wl[i+ae->idx].t=ae->macro[imacro].wc[i].t; - ae->wl[i+ae->idx].e=ae->macro[imacro].wc[i].e; - } - /* replace */ - idx=ae->idx; - for (i=0;imacro[imacro].nbword;j++) { - /* tags in upper case for replacement in quotes */ - if (StringIsQuote(ae->wl[j].w)) { - int lm,touched; - for (lm=touched=0;ae->wl[j].w[lm];lm++) { - if (ae->wl[j].w[lm]=='{') touched++; else if (ae->wl[j].w[lm]=='}') touched--; else if (touched) ae->wl[j].w[lm]=toupper(ae->wl[j].w[lm]); - } - } - ae->wl[j].w=TxtReplace(ae->wl[j].w,ae->macro[imacro].param[i],cpybackup[i].w,0); - } - MemFree(cpybackup[i].w); - } - MemFree(cpybackup); - /* macro replaced, need to rollback index */ - //ae->idx--; - } - } - /* a chaque appel de macro on incremente le compteur pour les labels locaux */ - ae->macrocounter++; - - return ae->wl; -} - -/* - ticker start, - ticker stop, -*/ -void __TICKER(struct s_assenv *ae) { - struct s_expr_dico *tvar; - struct s_ticker ticker; - int crc,i; - - if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { - crc=GetCRC(ae->wl[ae->idx+2].w); - - if (strcmp(ae->wl[ae->idx+1].w,"START")==0) { - /* is there already a counter? */ - for (i=0;iiticker;i++) { - if (ae->ticker[i].crc==crc && strcmp(ae->wl[ae->idx+2].w,ae->ticker[i].varname)==0) { - break; - } - } - if (i==ae->iticker) { - ticker.varname=TxtStrDup(ae->wl[ae->idx+2].w); - ticker.crc=crc; - ObjectArrayAddDynamicValueConcat((void **)&ae->ticker,&ae->iticker,&ae->mticker,&ticker,sizeof(struct s_ticker)); - } - ae->ticker[i].nopstart=ae->nop; - } else if (strcmp(ae->wl[ae->idx+1].w,"STOP")==0) { - for (i=0;iiticker;i++) { - if (ae->ticker[i].crc==crc && strcmp(ae->wl[ae->idx+2].w,ae->ticker[i].varname)==0) { - break; - } - } - if (iiticker) { - /* set var */ - if ((tvar=SearchDico(ae,ae->wl[ae->idx+2].w,crc))!=NULL) { - /* compute nop count */ - tvar->v=ae->nop-ae->ticker[i].nopstart; - } else { - /* create var with nop count */ - ExpressionSetDicoVar(ae,ae->wl[ae->idx+2].w,ae->nop-ae->ticker[i].nopstart); - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"TICKER not found\n"); - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"usage is TICKER start/stop,\n"); - } - ae->idx+=2; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"usage is TICKER start/stop,\n"); - } -} - -void __LET(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - ae->idx++; - ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); - RoundComputeExpression(ae,ae->wl[ae->idx].w,ae->codeadr,0,0); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LET useless winape directive need one expression\n"); - } -} - -void __RUN(struct s_assenv *ae) { - int ramconf=0xC0; - - if (!ae->wl[ae->idx].t) { - ae->current_run_idx=ae->idx+1; - if (ae->forcezx) { - if (!ae->wl[ae->idx].t) { - PushExpression(ae,ae->idx+1,E_EXPRESSION_ZXRUN); // delayed RUN value - PushExpression(ae,ae->idx+2,E_EXPRESSION_ZXSTACK); // delayed STACK value - ae->idx+=2; - } else { - ae->idx++; - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"usage is RUN , (ZX mode)\n"); - } - } else { - PushExpression(ae,ae->idx+1,E_EXPRESSION_RUN); // delayed RUN value - ae->idx++; - if (!ae->wl[ae->idx].t) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - ramconf=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); - ae->idx++; - if (ramconf<0xC0 || ramconf>0xFF) { - if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: ram configuration out of bound %X forced to #C0\n",GetCurrentFile(ae),ae->wl[ae->idx].l,ramconf); - } - } - } - } else { - if (ae->forcezx) MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"usage is RUN , (ZX mode)\n"); - else MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"usage is RUN [,]\n"); - } - ae->snapshot.ramconfiguration=ramconf; - if (ae->rundefined && !ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: run adress redefinition\n",GetCurrentFile(ae),ae->wl[ae->idx].l); - ae->rundefined=1; -} -void __BREAKPOINT(struct s_assenv *ae) { - struct s_breakpoint breakpoint={0}; - - if (ae->activebank>3) breakpoint.bank=1; - if (ae->wl[ae->idx].t) { - breakpoint.address=ae->codeadr; - ObjectArrayAddDynamicValueConcat((void **)&ae->breakpoint,&ae->ibreakpoint,&ae->maxbreakpoint,&breakpoint,sizeof(struct s_breakpoint)); - } else if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - breakpoint.address=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); - ObjectArrayAddDynamicValueConcat((void **)&ae->breakpoint,&ae->ibreakpoint,&ae->maxbreakpoint,&breakpoint,sizeof(struct s_breakpoint)); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is BREAKPOINT [adress]\n"); - } -} -void __SETCPC(struct s_assenv *ae) { - int mycpc; - - if (!ae->forcecpr) { - ae->forcesnapshot=1; - } else { - if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: Cannot SETCPC when already in cartridge output\n",GetCurrentFile(ae),ae->wl[ae->idx].l); - } - - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - mycpc=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); - ae->idx++; - switch (mycpc) { - case 0: - case 1: - case 2: - case 4: - case 5: - case 6: - ae->snapshot.CPCType=mycpc; - break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SETCPC directive has wrong value (0,1,2,4,5,6 only)\n"); - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SETCPC directive need one integer parameter\n"); - } -} -void __SETCRTC(struct s_assenv *ae) { - int mycrtc; - - if (!ae->forcecpr) { - ae->forcesnapshot=1; - } else { - if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: Cannot SETCRTC when already in cartridge output\n",GetCurrentFile(ae),ae->wl[ae->idx].l); - } - - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - mycrtc=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SETCRTC directive need one integer parameter\n"); - } - switch (mycrtc) { - case 0: - case 1: - case 2: - case 3: - case 4: - ae->snapshot.crtcstate.model=mycrtc; - break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SETCRTC directive has wrong value (0,1,2,3,4 only)\n"); - } -} - - -void __LIST(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LIST winape directive do not need parameter\n"); - } -} -void __NOLIST(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"NOLIST winape directive do not need parameter\n"); - } -} - -void __BRK(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BRK winape directive do not need parameter\n"); - } -} - -void __STOP(struct s_assenv *ae) { - rasm_printf(ae,"[%s:%d] STOP assembling requested\n",GetCurrentFile(ae),ae->wl[ae->idx].l); - while (ae->wl[ae->idx].t!=2) ae->idx++; - ae->idx--; - ae->stop=1; -} - -void __PRINT(struct s_assenv *ae) { - while (ae->wl[ae->idx].t!=1) { - if (!StringIsQuote(ae->wl[ae->idx+1].w)) { - char *string2print=NULL; - int hex=0,bin=0,entier=0; - - if (strncmp(ae->wl[ae->idx+1].w,"{HEX}",5)==0) { - string2print=TxtStrDup(ae->wl[ae->idx+1].w+5); - hex=1; - } else if (strncmp(ae->wl[ae->idx+1].w,"{HEX2}",6)==0) { - string2print=TxtStrDup(ae->wl[ae->idx+1].w+6); - hex=2; - } else if (strncmp(ae->wl[ae->idx+1].w,"{HEX4}",6)==0) { - string2print=TxtStrDup(ae->wl[ae->idx+1].w+6); - hex=4; - } else if (strncmp(ae->wl[ae->idx+1].w,"{HEX8}",6)==0) { - string2print=TxtStrDup(ae->wl[ae->idx+1].w+6); - hex=8; - } else if (strncmp(ae->wl[ae->idx+1].w,"{BIN}",5)==0) { - string2print=TxtStrDup(ae->wl[ae->idx+1].w+5); - bin=1; - } else if (strncmp(ae->wl[ae->idx+1].w,"{BIN8}",6)==0) { - string2print=TxtStrDup(ae->wl[ae->idx+1].w+6); - bin=8; - } else if (strncmp(ae->wl[ae->idx+1].w,"{BIN16}",7)==0) { - string2print=TxtStrDup(ae->wl[ae->idx+1].w+7); - bin=16; - } else if (strncmp(ae->wl[ae->idx+1].w,"{BIN32}",7)==0) { - string2print=TxtStrDup(ae->wl[ae->idx+1].w+7); - bin=32; - } else if (strncmp(ae->wl[ae->idx+1].w,"{INT}",5)==0) { - string2print=TxtStrDup(ae->wl[ae->idx+1].w+5); - entier=1; - } else { - string2print=TxtStrDup(ae->wl[ae->idx+1].w); - } - - ExpressionFastTranslate(ae,&string2print,1); - if (hex) { - int zv; - zv=RoundComputeExpressionCore(ae,string2print,ae->codeadr,0); - switch (hex) { - case 1: - if (zv&0xFFFFFF00) { - if (zv&0xFFFF0000) { - rasm_printf(ae,"#%-8.08X ",zv); - } else { - rasm_printf(ae,"#%-4.04X ",zv); - } - } else { - rasm_printf(ae,"#%-2.02X ",zv); - } - break; - case 2:rasm_printf(ae,"#%-2.02X ",zv);break; - case 4:rasm_printf(ae,"#%-4.04X ",zv);break; - case 8:rasm_printf(ae,"#%-8.08X ",zv);break; - } - } else if (bin) { - int zv,d; - zv=RoundComputeExpressionCore(ae,string2print,ae->codeadr,0); - /* remove useless sign bits */ - if (bin<32 && (zv&0xFFFF0000)==0xFFFF0000) { - zv&=0xFFFF; - } - switch (bin) { - case 1:if (zv&0xFF00) d=15; else d=7;break; - case 8:d=7;break; - case 16:d=15;break; - case 32:d=31;break; - } - rasm_printf(ae,"%%"); - for (;d>=0;d--) { - if ((zv>>d)&1) rasm_printf(ae,"1"); else rasm_printf(ae,"0"); - } - rasm_printf(ae," "); - } else if (entier) { - rasm_printf(ae,"%d ",(int)RoundComputeExpressionCore(ae,string2print,ae->codeadr,0)); - } else { - rasm_printf(ae,"%.2lf ",ComputeExpressionCore(ae,string2print,ae->codeadr,0)); - } - MemFree(string2print); - } else { - char *varbuffer; - int lm,touched; - lm=strlen(ae->wl[ae->idx+1].w)-2; - if (lm) { - varbuffer=MemMalloc(lm+2); - sprintf(varbuffer,"%-*.*s ",lm,lm,ae->wl[ae->idx+1].w+1); - /* need to upper case tags */ - for (lm=touched=0;varbuffer[lm];lm++) { - if (varbuffer[lm]=='{') touched++; else if (varbuffer[lm]=='}') touched--; else if (touched) varbuffer[lm]=toupper(varbuffer[lm]); - } - /* translate tag will check tag consistency */ - varbuffer=TranslateTag(ae,varbuffer,&touched,1,E_TAGOPTION_REMOVESPACE); - varbuffer=TxtReplace(varbuffer,"\\b","\b",0); - varbuffer=TxtReplace(varbuffer,"\\v","\v",0); - varbuffer=TxtReplace(varbuffer,"\\f","\f",0); - varbuffer=TxtReplace(varbuffer,"\\r","\r",0); - varbuffer=TxtReplace(varbuffer,"\\n","\n",0); - varbuffer=TxtReplace(varbuffer,"\\t","\t",0); - rasm_printf(ae,"%s ",varbuffer); - MemFree(varbuffer); - } - } - ae->idx++; - } - rasm_printf(ae,"\n"); -} - -void __FAIL(struct s_assenv *ae) { - __PRINT(ae); - __STOP(ae); - MaxError(ae); -} - -void __ALIGN(struct s_assenv *ae) { - int aval,ifill=-1; - - if (ae->io) { - ae->orgzone[ae->io-1].memend=ae->outputadr; - } - if (!ae->wl[ae->idx].t) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - aval=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); - ae->idx++; - /* align with fill ? */ - if (!ae->wl[ae->idx].t) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - ifill=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); - ae->idx++; - if (ifill<0 || ifill>255) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ALIGN fill value must be 0 to 255\n"); - ifill=0; - } - } - - if (aval<1 || aval>65535) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ALIGN boundary must be greater than zero and lower than 65536\n"); - aval=1; - } - - /* touch codeadr only if adress is misaligned */ - if (ae->codeadr%aval) { - if (ifill==-1) { - /* virtual ALIGN is moving outputadr the same value as codeadr move */ - ae->outputadr=ae->outputadr-(ae->codeadr%aval)+aval; - ae->codeadr=ae->codeadr-(ae->codeadr%aval)+aval; - } else { - /* physical ALIGN fill bytes */ - while (ae->codeadr%aval) { - ___output(ae,ifill); - ae->nop+=1; - } - } - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ALIGN [,fill] directive need one or two integers parameters\n"); - } -} - -void ___internal_skip_loop_block(struct s_assenv *ae, int eloopstyle) { - int *loopstyle=NULL; - int iloop=0,mloop=0; - int cidx; - - cidx=ae->idx+2; - - IntArrayAddDynamicValueConcat(&loopstyle,&iloop,&mloop,eloopstyle); - /* look for WEND */ - while (iloop) { - if (strcmp(ae->wl[cidx].w,"REPEAT")==0) { - if (ae->wl[cidx].t) { - IntArrayAddDynamicValueConcat(&loopstyle,&iloop,&mloop,E_LOOPSTYLE_REPEATUNTIL); - } else if (ae->wl[cidx+1].t) { - IntArrayAddDynamicValueConcat(&loopstyle,&iloop,&mloop,E_LOOPSTYLE_REPEATN); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid REPEAT syntax\n"); - } - } else if (strcmp(ae->wl[cidx].w,"WHILE")==0) { - if (!ae->wl[cidx].t && ae->wl[cidx+1].t) { - IntArrayAddDynamicValueConcat(&loopstyle,&iloop,&mloop,E_LOOPSTYLE_WHILE); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid WHILE syntax\n"); - } - } else if (strcmp(ae->wl[cidx].w,"WEND")==0) { - iloop--; - if (iloop<0) { - iloop=0; - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WEND encountered that was not expected\n"); - } else if (loopstyle[iloop]!=E_LOOPSTYLE_WHILE) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WEND encountered but expecting %s\n",loopstyle[iloop]==E_LOOPSTYLE_REPEATN?"REND":"UNTIL"); - } - } else if (strcmp(ae->wl[cidx].w,"REND")==0) { - iloop--; - if (iloop<0) { - iloop=0; - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"REND encountered that was not expected\n"); - } else if (loopstyle[iloop]!=E_LOOPSTYLE_REPEATN) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"REND encountered but expecting %s\n",loopstyle[iloop]==E_LOOPSTYLE_REPEATUNTIL?"UNTIL":"WEND"); - } - } else if (strcmp(ae->wl[cidx].w,"UNTIL")==0) { - iloop--; - if (iloop<0) { - iloop=0; - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"UNTIL encountered that was not expected\n"); - } else if (loopstyle[iloop]!=E_LOOPSTYLE_REPEATUNTIL) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"UNTIL encountered but expecting %s\n",loopstyle[iloop]==E_LOOPSTYLE_REPEATN?"REND":"WEND"); - } - } - while (!ae->wl[cidx].t) cidx++; - cidx++; - } - MemFree(loopstyle); - ae->idx=cidx-1; -} - -void __WHILE(struct s_assenv *ae) { - struct s_whilewend whilewend={0}; - - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - if (!ComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,2)) { - /* skip while block */ - ___internal_skip_loop_block(ae,E_LOOPSTYLE_WHILE); - return; - } else { - ae->idx++; - whilewend.start=ae->idx; - whilewend.cpt=0; - whilewend.value=ae->whilecounter; - whilewend.maxim=ae->imacropos; - whilewend.while_counter=1; - ae->whilecounter++; - /* pour gérer les macros situés dans le while précedent après un repeat/while courant */ - if (ae->iw) whilewend.maxim=ae->whilewend[ae->iw-1].maxim; - if (ae->ir && ae->repeat[ae->ir-1].maxim>whilewend.maxim) whilewend.maxim=ae->repeat[ae->ir-1].maxim; - ObjectArrayAddDynamicValueConcat((void**)&ae->whilewend,&ae->iw,&ae->mw,&whilewend,sizeof(whilewend)); - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is WHILE \n"); - } -} -void __WEND(struct s_assenv *ae) { - if (ae->iw>0) { - if (ae->wl[ae->idx].t==1) { - if (ComputeExpression(ae,ae->wl[ae->whilewend[ae->iw-1].start].w,ae->codeadr,0,2)) { - if (ae->whilewend[ae->iw-1].while_counter>65536) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Bypass infinite WHILE loop\n"); - ae->iw--; - /* refresh macro check index */ - if (ae->iw) ae->imacropos=ae->whilewend[ae->iw-1].maxim; - } else { - ae->whilewend[ae->iw-1].cpt++; /* for local label */ - ae->whilewend[ae->iw-1].while_counter++; - ae->idx=ae->whilewend[ae->iw-1].start; - /* refresh macro check index */ - ae->imacropos=ae->whilewend[ae->iw-1].maxim; - } - } else { - ae->iw--; - /* refresh macro check index */ - if (ae->iw) ae->imacropos=ae->whilewend[ae->iw-1].maxim; - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WEND does not need any parameter\n"); - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WEND encounter whereas there is no referent WHILE\n"); - } -} - -void __REPEAT(struct s_assenv *ae) { - struct s_repeat currepeat={0}; - struct s_expr_dico *rvar; - int *loopstyle; - int iloop,mloop; - int cidx,crc; - - if (ae->wl[ae->idx+1].t!=2) { - if (ae->wl[ae->idx].t==0) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - currepeat.cpt=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,0,0,0); - if (!currepeat.cpt) { - /* skip repeat block */ - ___internal_skip_loop_block(ae,E_LOOPSTYLE_REPEATN); - return; - } else if (currepeat.cpt<1 || currepeat.cpt>65536) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Repeat value (%d) must be from 1 to 65535. Skipping block\n",currepeat.cpt); - ___internal_skip_loop_block(ae,E_LOOPSTYLE_REPEATN); - return; - } - ae->idx++; - currepeat.start=ae->idx; - if (ae->wl[ae->idx].t==0) { - ae->idx++; - if (ae->wl[ae->idx].t==1) { - /* la variable peut exister -> OK */ - crc=GetCRC(ae->wl[ae->idx].w); - if ((rvar=SearchDico(ae,ae->wl[ae->idx].w,crc))!=NULL) { - rvar->v=1; - } else { - /* mais ne peut être un label ou un alias */ - ExpressionSetDicoVar(ae,ae->wl[ae->idx].w, 1); - } - currepeat.repeatvar=ae->wl[ae->idx].w; - currepeat.repeatcrc=crc; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"extended syntax is REPEAT ,\n"); - } - } - } else { - currepeat.start=ae->idx; - currepeat.cpt=-1; - } - currepeat.value=ae->repeatcounter; - currepeat.repeat_counter=1; - ae->repeatcounter++; - /* pour gérer les macros situés dans le repeat précedent après le repeat courant */ - if (ae->ir) currepeat.maxim=ae->repeat[ae->ir-1].maxim; - if (ae->iw && ae->whilewend[ae->iw-1].maxim>currepeat.maxim) currepeat.maxim=ae->whilewend[ae->iw-1].maxim; - if (ae->imacropos>currepeat.maxim) currepeat.maxim=ae->imacropos; - ObjectArrayAddDynamicValueConcat((void**)&ae->repeat,&ae->ir,&ae->mr,&currepeat,sizeof(currepeat)); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"wrong REPEAT usage\n"); - } -} - -void __REND(struct s_assenv *ae) { - struct s_expr_dico *rvar; - if (ae->ir>0) { - if (ae->repeat[ae->ir-1].cpt==-1) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"REND encounter whereas referent REPEAT was waiting for UNTIL\n"); - } else { - ae->repeat[ae->ir-1].cpt--; - ae->repeat[ae->ir-1].repeat_counter++; - if ((rvar=SearchDico(ae,ae->repeat[ae->ir-1].repeatvar,ae->repeat[ae->ir-1].repeatcrc))!=NULL) { - rvar->v=ae->repeat[ae->ir-1].repeat_counter; - } - if (ae->repeat[ae->ir-1].cpt) { - ae->idx=ae->repeat[ae->ir-1].start; - /* refresh macro check index */ - ae->imacropos=ae->repeat[ae->ir-1].maxim; - } else { - ae->ir--; - /* refresh macro check index */ - if (ae->ir) ae->imacropos=ae->repeat[ae->ir-1].maxim; - } - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"REND encounter whereas there is no referent REPEAT\n"); - } -} - -void __UNTIL(struct s_assenv *ae) { - if (ae->ir>0) { - if (ae->repeat[ae->ir-1].cpt>=0) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"[%s:%d] UNTIL encounter whereas referent REPEAT n was waiting for REND\n"); - } else { - if (ae->wl[ae->idx].t==0 && ae->wl[ae->idx+1].t==1) { - ae->repeat[ae->ir-1].repeat_counter++; - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - if (!ComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,2)) { - if (ae->repeat[ae->ir-1].repeat_counter>65536) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Bypass infinite REPEAT loop\n"); - ae->ir--; - /* refresh macro check index */ - if (ae->ir) ae->imacropos=ae->repeat[ae->ir-1].maxim; - } else { - ae->idx=ae->repeat[ae->ir-1].start; - ae->repeat[ae->ir-1].cpt--; /* for local label */ - /* refresh macro check index */ - ae->imacropos=ae->repeat[ae->ir-1].maxim; - } - } else { - ae->ir--; - /* refresh macro check index */ - if (ae->ir) ae->imacropos=ae->repeat[ae->ir-1].maxim; - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"UNTIL need one expression/evaluation as parameter\n"); - } - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"UNTIL encounter whereas there is no referent REPEAT\n"); - } -} - -void __ASSERT(struct s_assenv *ae) { - char Dot3[4]; - int rexpr; - - if (!ae->wl[ae->idx].t) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - if (strlen(ae->wl[ae->idx+1].w)>29) strcpy(Dot3,"..."); else strcpy(Dot3,""); - rexpr=!!RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,1); - if (!rexpr) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx+1].l,"ASSERT %.29s%s failed with ",ae->wl[ae->idx+1].w,Dot3); - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,1); - rasm_printf(ae,"%s\n",ae->wl[ae->idx+1].w); - if (!ae->wl[ae->idx+1].t) { - ae->idx++; - rasm_printf(ae,"-> "); - __PRINT(ae); - } - __STOP(ae); - } else { - while (!ae->wl[ae->idx].t) ae->idx++; - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ASSERT need one expression\n"); - } -} - -void __IF(struct s_assenv *ae) { - struct s_ifthen ifthen={0}; - int rexpr; - - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - rexpr=!!RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,1); - ifthen.v=rexpr; - ifthen.filename=GetCurrentFile(ae); - ifthen.line=ae->wl[ae->idx].l; - ifthen.type=E_IFTHEN_TYPE_IF; - ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IF need one expression\n"); - } -} - -void __IF_light(struct s_assenv *ae) { - struct s_ifthen ifthen={0}; - - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - /* do not need to compute the value in shadow execution */ - ifthen.v=0; - ifthen.filename=GetCurrentFile(ae); - ifthen.line=ae->wl[ae->idx].l; - ifthen.type=E_IFTHEN_TYPE_IF; - ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IF need one expression\n"); - } -} - -/* test if a label or a variable where used before */ -void __IFUSED(struct s_assenv *ae) { - struct s_ifthen ifthen={0}; - int rexpr,crc; - - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - crc=GetCRC(ae->wl[ae->idx+1].w); - if ((SearchDico(ae,ae->wl[ae->idx+1].w,crc))!=NULL) { - rexpr=1; - } else { - if ((SearchLabel(ae,ae->wl[ae->idx+1].w,crc))!=NULL) { - rexpr=1; - } else { - if ((SearchAlias(ae,crc,ae->wl[ae->idx+1].w))!=-1) { - rexpr=1; - } else { - rexpr=SearchUsed(ae,ae->wl[ae->idx+1].w,crc); - } - } - } - ifthen.v=rexpr; - ifthen.filename=GetCurrentFile(ae); - ifthen.line=ae->wl[ae->idx].l; - ifthen.type=E_IFTHEN_TYPE_IFUSED; - ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IFUSED need one variable or label\n"); - } -} -void __IFNUSED(struct s_assenv *ae) { - __IFUSED(ae); - ae->ifthen[ae->ii-1].v=1-ae->ifthen[ae->ii-1].v; - ae->ifthen[ae->ii-1].type=E_IFTHEN_TYPE_IFNUSED; -} -void __IFUSED_light(struct s_assenv *ae) { - struct s_ifthen ifthen={0}; - - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - ifthen.v=0; - ifthen.filename=GetCurrentFile(ae); - ifthen.line=ae->wl[ae->idx].l; - ifthen.type=E_IFTHEN_TYPE_IFUSED; - ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IFUSED need one variable or label\n"); - } -} -void __IFNUSED_light(struct s_assenv *ae) { - __IFUSED_light(ae); - ae->ifthen[ae->ii-1].type=E_IFTHEN_TYPE_IFNUSED; -} - -/* test if a label or a variable exists */ -void __IFDEF(struct s_assenv *ae) { - struct s_ifthen ifthen={0}; - int rexpr,crc; - - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - crc=GetCRC(ae->wl[ae->idx+1].w); - if ((SearchDico(ae,ae->wl[ae->idx+1].w,crc))!=NULL) { - rexpr=1; - } else { - if ((SearchLabel(ae,ae->wl[ae->idx+1].w,crc))!=NULL) { - rexpr=1; - } else { - if ((SearchAlias(ae,crc,ae->wl[ae->idx+1].w))!=-1) { - rexpr=1; - } else { - if (SearchMacro(ae,crc,ae->wl[ae->idx+1].w)>=0) { - rexpr=1; - } else { - rexpr=0; - } - } - } - } - ifthen.v=rexpr; - ifthen.filename=GetCurrentFile(ae); - ifthen.line=ae->wl[ae->idx].l; - ifthen.type=E_IFTHEN_TYPE_IFDEF; - ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IFDEF need one variable or label\n"); - } -} -void __IFDEF_light(struct s_assenv *ae) { - struct s_ifthen ifthen={0}; - - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - ifthen.v=0; - ifthen.filename=GetCurrentFile(ae); - ifthen.line=ae->wl[ae->idx].l; - ifthen.type=E_IFTHEN_TYPE_IFDEF; - ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"GetCurrentFile(ae),ae->wl[ae->idx].l[%s:%d] FATAL - IFDEF need one variable or label\n"); - } -} -void __IFNDEF(struct s_assenv *ae) { - struct s_expr_dico *curdic=NULL; - struct s_label *curlabel=NULL; - struct s_ifthen ifthen={0}; - int rexpr,crc; - - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - crc=GetCRC(ae->wl[ae->idx+1].w); - if ((SearchDico(ae,ae->wl[ae->idx+1].w,crc))!=NULL) { - rexpr=0; - } else { - if ((SearchLabel(ae,ae->wl[ae->idx+1].w,crc))!=NULL) { - rexpr=0; - } else { - if ((SearchAlias(ae,crc,ae->wl[ae->idx+1].w))!=-1) { - rexpr=0; - } else { - if (SearchMacro(ae,crc,ae->wl[ae->idx+1].w)>=0) { - rexpr=0; - } else { - rexpr=1; - } - } - } - } - ifthen.v=rexpr; - ifthen.filename=GetCurrentFile(ae); - ifthen.line=ae->wl[ae->idx].l; - ifthen.type=E_IFTHEN_TYPE_IFNDEF; - ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IFNDEF need one variable or label\n"); - } -} -void __IFNDEF_light(struct s_assenv *ae) { - struct s_expr_dico *curdic=NULL; - struct s_label *curlabel=NULL; - struct s_ifthen ifthen={0}; - - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - ifthen.v=0; - ifthen.filename=GetCurrentFile(ae); - ifthen.line=ae->wl[ae->idx].l; - ifthen.type=E_IFTHEN_TYPE_IFNDEF; - ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IFNDEF need one variable or label\n",GetCurrentFile(ae),ae->wl[ae->idx].l); - } -} - -void __UNDEF(struct s_assenv *ae) { - - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - /* no error when the variable to UNDEF does not exist */ - DelDico(ae,ae->wl[ae->idx+1].w,GetCRC(ae->wl[ae->idx+1].w)); - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is UNDEF \n"); - } - -} - - -void __SWITCH(struct s_assenv *ae) { - struct s_switchcase curswitch={0}; - - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - /* switch store the value */ - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - curswitch.refval=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,1); - ObjectArrayAddDynamicValueConcat((void**)&ae->switchcase,&ae->isw,&ae->msw,&curswitch,sizeof(curswitch)); - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SWITCH need one expression\n"); - } -} -void __CASE(struct s_assenv *ae) { - int rexpr; - - if (ae->isw) { - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - rexpr=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,1); - - if (ae->switchcase[ae->isw-1].refval==rexpr) { - ae->switchcase[ae->isw-1].execute=1; - ae->switchcase[ae->isw-1].casematch=1; - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CASE not need one parameter\n"); - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CASE encounter whereas there is no referent SWITCH\n"); - } -} -void __DEFAULT(struct s_assenv *ae) { - - if (ae->isw) { - if (ae->wl[ae->idx].t==1) { - /* aucun match avant, on active, sinon on laisse tel quel */ - if (!ae->switchcase[ae->isw-1].casematch) { - ae->switchcase[ae->isw-1].execute=1; - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFAULT do not need parameter\n"); - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFAULT encounter whereas there is no referent SWITCH\n"); - } -} -void __BREAK(struct s_assenv *ae) { - - if (ae->isw) { - if (ae->wl[ae->idx].t==1) { - ae->switchcase[ae->isw-1].execute=0; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BREAK do not need parameter\n"); - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BREAK encounter whereas there is no referent SWITCH\n"); - } -} -void __SWITCH_light(struct s_assenv *ae) { - struct s_switchcase curswitch={0}; - - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - /* shadow execution */ - curswitch.refval=0; - curswitch.execute=0; - ObjectArrayAddDynamicValueConcat((void**)&ae->switchcase,&ae->isw,&ae->msw,&curswitch,sizeof(curswitch)); - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SWITCH need one expression\n"); - } -} -void __CASE_light(struct s_assenv *ae) { - if (ae->isw) { - /* shadowed execution */ - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CASE encounter whereas there is no referent SWITCH\n"); - } -} -void __DEFAULT_light(struct s_assenv *ae) { - - if (ae->isw) { - /* shadowed execution */ - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFAULT encounter whereas there is no referent SWITCH\n"); - } -} -void __BREAK_light(struct s_assenv *ae) { - if (ae->isw) { - /* shadowed execution */ - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BREAK encounter whereas there is no referent SWITCH\n"); - } -} -void __ENDSWITCH(struct s_assenv *ae) { - if (ae->isw) { - if (ae->wl[ae->idx].t==1) { - ae->isw--; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ENDSWITCH does not need any parameter\n"); - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ENDSWITCH encounter whereas there is no referent SWITCH\n"); - } -} - -void __IFNOT(struct s_assenv *ae) { - struct s_ifthen ifthen={0}; - int rexpr; - - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - rexpr=!RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,1); - ifthen.v=rexpr; - ifthen.filename=GetCurrentFile(ae); - ifthen.line=ae->wl[ae->idx].l; - ifthen.type=E_IFTHEN_TYPE_IFNOT; - ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); - //IntArrayAddDynamicValueConcat(&ae->ifthen,&ae->ii,&ae->mi,rexpr); - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IFNOT need one expression\n"); - } -} -void __IFNOT_light(struct s_assenv *ae) { - struct s_ifthen ifthen={0}; - - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - ifthen.v=0; - ifthen.filename=GetCurrentFile(ae); - ifthen.line=ae->wl[ae->idx].l; - ifthen.type=E_IFTHEN_TYPE_IFNOT; - ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); - //IntArrayAddDynamicValueConcat(&ae->ifthen,&ae->ii,&ae->mi,rexpr); - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IFNOT need one expression\n"); - } -} - -void __ELSE(struct s_assenv *ae) { - if (ae->ii) { - if (ae->wl[ae->idx].t==1) { - /* ELSE a executer seulement si celui d'avant est a zero */ - switch (ae->ifthen[ae->ii-1].v) { - case -1:break; - case 0:ae->ifthen[ae->ii-1].v=1;break; - case 1:ae->ifthen[ae->ii-1].v=0;break; - } - ae->ifthen[ae->ii-1].type=E_IFTHEN_TYPE_ELSE; - ae->ifthen[ae->ii-1].line=ae->wl[ae->idx].l; - ae->ifthen[ae->ii-1].filename=GetCurrentFile(ae); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ELSE does not need any parameter\n"); - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ELSE encounter whereas there is no referent IF\n"); - } -} -void __ELSEIF(struct s_assenv *ae) { - - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - ae->ifthen[ae->ii-1].type=E_IFTHEN_TYPE_ELSEIF; - ae->ifthen[ae->ii-1].line=ae->wl[ae->idx].l; - ae->ifthen[ae->ii-1].filename=GetCurrentFile(ae); - if (ae->ifthen[ae->ii-1].v) { - /* il faut signifier aux suivants qu'on va jusqu'au ENDIF */ - ae->ifthen[ae->ii-1].v=-1; - } else { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - ae->ifthen[ae->ii-1].v=!!RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,1); - } - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ELSEIF need one expression\n"); - } -} -void __ELSEIF_light(struct s_assenv *ae) { - - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - ae->ifthen[ae->ii-1].type=E_IFTHEN_TYPE_ELSEIF; - ae->ifthen[ae->ii-1].line=ae->wl[ae->idx].l; - ae->ifthen[ae->ii-1].filename=GetCurrentFile(ae); - if (ae->ifthen[ae->ii-1].v) { - /* il faut signifier aux suivants qu'on va jusqu'au ENDIF */ - ae->ifthen[ae->ii-1].v=-1; - } else { - ae->ifthen[ae->ii-1].v=0; - } - ae->idx++; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ELSEIF need one expression\n"); - } -} -void __ENDIF(struct s_assenv *ae) { - if (ae->ii) { - if (ae->wl[ae->idx].t==1) { - ae->ii--; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ENDIF does not need any parameter\n"); - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ENDIF encounter whereas there is no referent IF\n"); - } -} - -void __internal_PROTECT(struct s_assenv *ae, int memstart, int memend) { - struct s_orgzone orgzone={0}; - - /* add a fake ORG zone */ - ObjectArrayAddDynamicValueConcat((void**)&ae->orgzone,&ae->io,&ae->mo,&orgzone,sizeof(orgzone)); - /* then switch it with the current ORG */ - orgzone=ae->orgzone[ae->io-2]; - ae->orgzone[ae->io-2].memstart=memstart; - ae->orgzone[ae->io-2].memend=memend; - ae->orgzone[ae->io-2].ibank=ae->activebank; - ae->orgzone[ae->io-2].protect=1; - ae->orgzone[ae->io-1]=orgzone; -} - -void __PROTECT(struct s_assenv *ae) { - int memstart,memend; - - if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - ExpressionFastTranslate(ae,&ae->wl[ae->idx+2].w,0); - memstart=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,0,0,0); - memend=RoundComputeExpression(ae,ae->wl[ae->idx+2].w,0,0,0); - __internal_PROTECT(ae,memstart,memend); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"PROTECT need two parameters: startadr,endadr\n"); - } -} - -void ___org_close(struct s_assenv *ae) { - if (ae->lz>=0) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot ORG inside a LZ section\n"); - return; - } - __internal_UpdateLZBlockIfAny(ae); - /* close current ORG */ - if (ae->io) { - ae->orgzone[ae->io-1].memend=ae->outputadr; - } -} - -void ___org_new(struct s_assenv *ae, int nocode) { - struct s_orgzone orgzone={0}; - int i; - - /* check current ORG request */ - for (i=0;iio;i++) { - /* aucun contrôle sur les ORG non écrits ou en NOCODE */ - if (ae->orgzone[i].memstart!=ae->orgzone[i].memend && !ae->orgzone[i].nocode) { - if (ae->orgzone[i].ibank==ae->activebank) { - if (ae->outputadrorgzone[i].memend && ae->outputadr>=ae->orgzone[i].memstart) { - if (ae->orgzone[i].protect) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ORG located a PROTECTED section [#%04X-#%04X-B%d] file [%s] line %d\n",ae->orgzone[i].memstart,ae->orgzone[i].memend,ae->orgzone[i].ibank<32?ae->orgzone[i].ibank:0,ae->filename[ae->orgzone[i].ifile],ae->orgzone[i].iline); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ORG (output at #%04X) located in a previous ORG section [#%04X-#%04X-B%d] file [%s] line %d\n",ae->outputadr,ae->orgzone[i].memstart,ae->orgzone[i].memend,ae->orgzone[i].ibank<32?ae->orgzone[i].ibank:0,ae->filename[ae->orgzone[i].ifile],ae->orgzone[i].iline); - } - } - } - } - } - - OverWriteCheck(ae); - /* if there was a crunch block before, now closed */ - if (ae->lz>=0) { - ae->lz=-1; - } - orgzone.memstart=ae->outputadr; - orgzone.ibank=ae->activebank; - orgzone.ifile=ae->wl[ae->idx].ifile; - orgzone.iline=ae->wl[ae->idx].l; - orgzone.nocode=ae->nocode=nocode; - - if (nocode) { - ___output=___internal_output_nocode; - } else { - ___output=___internal_output; - } - - ObjectArrayAddDynamicValueConcat((void**)&ae->orgzone,&ae->io,&ae->mo,&orgzone,sizeof(orgzone)); -} - -void __ORG(struct s_assenv *ae) { - ___org_close(ae); - - if (ae->wl[ae->idx+1].t!=2) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); - ae->codeadr=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->outputadr,0,0); - if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+2].w,0); - ae->outputadr=RoundComputeExpression(ae,ae->wl[ae->idx+2].w,ae->outputadr,0,0); - ae->idx+=2; - } else { - ae->outputadr=ae->codeadr; - ae->idx++; - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"[%s:%d] ORG code location[,output location]\n"); - return; - } - - ___org_new(ae,ae->nocode); -} -void __NOCODE(struct s_assenv *ae) { - if (ae->wl[ae->idx].t==1) { - ___org_close(ae); - ae->codeadrbackup=ae->codeadr; - ae->outputadrbackup=ae->outputadr; - ___org_new(ae,1); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"NOCODE directive does not need parameter\n"); - } -} -void __CODE(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t) { - if (strcmp(ae->wl[ae->idx+1].w,"SKIP")==0) { - ___org_close(ae); - ae->codeadr=ae->codeadrbackup; - ae->outputadr=ae->outputadrbackup; - ___org_new(ae,1); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"unknown parameter for CODE directive\n"); - } - ae->idx++; - } else if (ae->wl[ae->idx].t==1) { - ___org_close(ae); - ___org_new(ae,0); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CODE directive does not need parameter\n"); - } -} -void __STRUCT(struct s_assenv *ae) { - #undef FUNC - #define FUNC "__STRUCT" - struct s_rasmstructfield rasmstructfield={0}; - struct s_rasmstruct rasmstruct={0}; - struct s_rasmstruct rasmstructalias={0}; - struct s_label curlabel={0}; - int crc,i,j,irs; - /* filler */ - int localsize,cursize; - double zeval; - - if (!ae->wl[ae->idx].t) { - if (ae->wl[ae->idx+1].t) { - /************************************************** - s t r u c t u r e d e c l a r a t i o n - **************************************************/ - if (!ae->getstruct) { - /* cannot be an existing label or EQU (but variable ok) */ - crc=GetCRC(ae->wl[ae->idx+1].w); - if ((SearchLabel(ae,ae->wl[ae->idx+1].w,crc))!=NULL || (SearchAlias(ae,crc,ae->wl[ae->idx+1].w))!=-1) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"STRUCT name must be different from existing labels ou aliases\n"); - } else { - ae->backup_filename=GetCurrentFile(ae); - ae->backup_line=ae->wl[ae->idx].l; - ae->backup_outputadr=ae->outputadr; - ae->backup_codeadr=ae->codeadr; - ae->getstruct=1; - /* STRUCT = NOCODE + ORG 0 */ - ___org_close(ae); - ae->codeadr=0; - ___org_new(ae,1); - /* create struct */ - rasmstruct.name=TxtStrDup(ae->wl[ae->idx+1].w); - rasmstruct.crc=GetCRC(rasmstruct.name); - ObjectArrayAddDynamicValueConcat((void **)&ae->rasmstruct,&ae->irasmstruct,&ae->mrasmstruct,&rasmstruct,sizeof(rasmstruct)); - ae->idx++; - - /* wrapper for data capture */ - instruction[ICRC_DEFB].makemnemo=_DEFB_struct;instruction[ICRC_DB].makemnemo=_DEFB_struct; - instruction[ICRC_DEFW].makemnemo=_DEFW_struct;instruction[ICRC_DW].makemnemo=_DEFW_struct; - instruction[ICRC_DEFI].makemnemo=_DEFI_struct; - instruction[ICRC_DEFR].makemnemo=_DEFR_struct;instruction[ICRC_DR].makemnemo=_DEFR_struct; - instruction[ICRC_DEFS].makemnemo=_DEFS_struct;instruction[ICRC_DS].makemnemo=_DEFS_struct; - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"STRUCT cannot be declared inside previous opened STRUCT [%s] Line %d\n",ae->backup_filename,ae->backup_line); - } - } else { - /************************************************** - s t r u c t u r e i n s e r t i o n - **************************************************/ - int nbelem=1; -#if TRACE_STRUCT -printf("structure insertion\n"); -#endif - /* insert struct param1 in memory with name param2 */ - crc=GetCRC(ae->wl[ae->idx+1].w); - /* look for existing struct */ - for (irs=0;irsirasmstruct;irs++) { - if (ae->rasmstruct[irs].crc==crc && strcmp(ae->rasmstruct[irs].name,ae->wl[ae->idx+1].w)==0) break; - } - if (irs==ae->irasmstruct) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Unknown STRUCT %s\n",ae->wl[ae->idx+1].w); - } else { - /* create alias for sizeof */ - if (!ae->getstruct) { - if (ae->wl[ae->idx+2].w[0]=='@') { - rasmstructalias.name=MakeLocalLabel(ae,ae->wl[ae->idx+2].w,NULL); - } else { - rasmstructalias.name=TxtStrDup(ae->wl[ae->idx+2].w); - } - } else { -#if TRACE_STRUCT -printf("struct [%s] inside struct\n",ae->wl[ae->idx+2].w); -#endif - /* struct inside struct */ - rasmstructalias.name=MemMalloc(strlen(ae->rasmstruct[ae->irasmstruct-1].name)+2+strlen(ae->wl[ae->idx+2].w)); - sprintf(rasmstructalias.name,"%s.%s",ae->rasmstruct[ae->irasmstruct-1].name,ae->wl[ae->idx+2].w); - } - rasmstructalias.crc=GetCRC(rasmstructalias.name); - rasmstructalias.size=ae->rasmstruct[irs].size; - rasmstructalias.ptr=ae->codeadr; -#if TRACE_STRUCT -printf("structalias [%s] ptr=%d size=%d\n",rasmstructalias.name,rasmstructalias.ptr,rasmstructalias.size); -#endif - /* extra parameter to declare an array? */ - if (!ae->wl[ae->idx+2].t && !StringIsQuote(ae->wl[ae->idx+3].w)) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+3].w,0); - nbelem=RoundComputeExpression(ae,ae->wl[ae->idx+3].w,ae->outputadr,0,0); - if (nbelem<1) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Struct array need a positive number of elements!\n"); - nbelem=1; - } - ae->idx++; - } - rasmstructalias.nbelem=nbelem; -#if TRACE_STRUCT -printf("EVOL 119 - tableau! %d elem(s)\n",nbelem); -#endif - ObjectArrayAddDynamicValueConcat((void **)&ae->rasmstructalias,&ae->irasmstructalias,&ae->mrasmstructalias,&rasmstructalias,sizeof(rasmstructalias)); - - /* create label for global struct ptr */ - curlabel.iw=-1; - curlabel.ptr=ae->codeadr; - if (!ae->getstruct) { - if (ae->wl[ae->idx+2].w[0]=='@') curlabel.name=MakeLocalLabel(ae,ae->wl[ae->idx+2].w,NULL); else curlabel.name=TxtStrDup(ae->wl[ae->idx+2].w); - curlabel.crc=GetCRC(curlabel.name); - PushLabelLight(ae,&curlabel); - } else { - /* or check for non-local name in struct declaration */ - if (ae->wl[ae->idx+2].w[0]=='@') { - MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"Meaningless use of local label in a STRUCT definition\n"); - } else { - curlabel.name=TxtStrDup(rasmstructalias.name); - curlabel.crc=GetCRC(curlabel.name); - PushLabelLight(ae,&curlabel); - } - } - - /* first field is in fact the very beginning of the structure */ - if (ae->getstruct) { - rasmstructfield.name=TxtStrDup(ae->wl[ae->idx+2].w); - rasmstructfield.offset=ae->codeadr; - ObjectArrayAddDynamicValueConcat((void **)&ae->rasmstruct[ae->irasmstruct-1].rasmstructfield, - &ae->rasmstruct[ae->irasmstruct-1].irasmstructfield,&ae->rasmstruct[ae->irasmstruct-1].mrasmstructfield, - &rasmstructfield,sizeof(rasmstructfield)); - } - - /* create subfields */ -#if TRACE_STRUCT -printf("create subfields\n"); -#endif - curlabel.iw=-1; - curlabel.ptr=ae->codeadr; - for (i=0;irasmstruct[irs].irasmstructfield;i++) { - curlabel.ptr=ae->codeadr+ae->rasmstruct[irs].rasmstructfield[i].offset; - if (!ae->getstruct) { - curlabel.name=MemMalloc(strlen(ae->wl[ae->idx+2].w)+strlen(ae->rasmstruct[irs].rasmstructfield[i].name)+2); - sprintf(curlabel.name,"%s.%s",ae->wl[ae->idx+2].w,ae->rasmstruct[irs].rasmstructfield[i].name); - if (ae->wl[ae->idx+2].w[0]=='@') { - char *newlabel; - newlabel=MakeLocalLabel(ae,curlabel.name,NULL); - MemFree(curlabel.name); - curlabel.name=newlabel; - } - curlabel.crc=GetCRC(curlabel.name); - PushLabelLight(ae,&curlabel); - /* are we using a struct in a struct definition? */ - } else { - /* copy structname+label+offset in the structure */ - rasmstructfield.name=MemMalloc(strlen(ae->wl[ae->idx+2].w)+strlen(ae->rasmstruct[irs].rasmstructfield[i].name)+2); - sprintf(rasmstructfield.name,"%s.%s",ae->wl[ae->idx+2].w,ae->rasmstruct[irs].rasmstructfield[i].name); - rasmstructfield.offset=curlabel.ptr; - ObjectArrayAddDynamicValueConcat((void **)&ae->rasmstruct[ae->irasmstruct-1].rasmstructfield, - &ae->rasmstruct[ae->irasmstruct-1].irasmstructfield,&ae->rasmstruct[ae->irasmstruct-1].mrasmstructfield, - &rasmstructfield,sizeof(rasmstructfield)); - - /* need to push also generic label */ - curlabel.name=MemMalloc(strlen(ae->rasmstruct[ae->irasmstruct-1].name)+strlen(rasmstructfield.name)+2); /* overwrite PTR */ - sprintf(curlabel.name,"%s.%s",ae->rasmstruct[ae->irasmstruct-1].name,rasmstructfield.name); - curlabel.crc=GetCRC(curlabel.name); - PushLabelLight(ae,&curlabel); - } - } - - /* is there any filler in the declaration? */ - localsize=0; - - /* déterminer si on est en remplissage par défaut ou remplissage surchargé */ - - - - - -#if TRACE_STRUCT -printf("struct new behaviour (scan for %d fields)\n",ae->rasmstruct[irs].irasmstructfield); -#endif -#if 0 - for (i=0;irasmstruct[irs].irasmstructfield;i++) { - - if (!ae->wl[ae->idx+2+i].t || i+1>=ae->rasmstruct[irs].irasmstructfield) { - /* si le champ est sur le même offset que le précédent, on le saute */ - if (i && ae->rasmstruct[irs].rasmstructfield[i].offset>ae->rasmstruct[irs].rasmstructfield[i-1].offset) continue; - -#if TRACE_STRUCT -printf("get field? (%d)\n",irs); -#endif - if (!StringIsQuote(ae->wl[ae->idx+i].w)) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+i].w,1); - zeval=RoundComputeExpressionCore(ae,ae->wl[ae->idx+i].w,ae->codeadr,0); - } else { - // push string - } - - localsize+=ae->rasmstruct[irs].rasmstructfield[i].size; - - /* pour du single shot ? - pushbyte(s) at ae->codeadr+ae->rasmstruct[irs].rasmstructfield[i].offset - */ - - //ae->rasmstruct[irs].size; - - } else { -#if TRACE_STRUCT -printf("*break*\n"); -#endif - break; - } - } -#endif - - /* (LEGACY) filler, on balance des zéros */ -#if TRACE_STRUCT -printf("struct (almost) legacy filler from %d to %d-1\n",localsize,ae->rasmstruct[irs].size); -#endif - while (nbelem) { - for (i=cursize=0;irasmstruct[irs].irasmstructfield && cursizerasmstruct[irs].rasmstructfield[i].size; - } - for (;irasmstruct[irs].irasmstructfield;i++) { - for (j=0;jrasmstruct[irs].rasmstructfield[i].idata;j++) { - ___output(ae,ae->rasmstruct[irs].rasmstructfield[i].data[j]); - } - } - nbelem--; - } - -#if 0 - for (i=localsize;irasmstruct[irs].size;i++) ___output(ae,0); -#endif - ae->idx+=2; // probablement à revoir dans le cas d'une init!!! - } - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"STRUCT directive needs one or two parameters\n"); - } -} -void __ENDSTRUCT(struct s_assenv *ae) { - #undef FUNC - #define FUNC "__ENDSTRUCT" - struct s_label curlabel={0}; - int i,newlen; -#if TRACE_STRUCT - printf("endstruct\n"); -#endif - - if (!ae->wl[ae->idx].t) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ENDSTRUCT directive does not need parameter\n"); - } else { - if (ae->getstruct) { - ae->rasmstruct[ae->irasmstruct-1].size=ae->codeadr; - ae->getstruct=0; - - /* SIZEOF like Vasm with struct name */ - curlabel.name=TxtStrDup(ae->rasmstruct[ae->irasmstruct-1].name); - curlabel.crc=ae->rasmstruct[ae->irasmstruct-1].crc; - curlabel.iw=-1; - curlabel.ptr=ae->rasmstruct[ae->irasmstruct-1].size; - PushLabelLight(ae,&curlabel); - - /* compute size for each field */ - newlen=strlen(ae->rasmstruct[ae->irasmstruct-1].name)+2; - for (i=0;irasmstruct[ae->irasmstruct-1].irasmstructfield-1;i++) { - ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].size=ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i+1].offset-ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].offset; - ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].fullname=MemMalloc(newlen+strlen(ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].name)); - sprintf(ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].fullname,"%s.%s",ae->rasmstruct[ae->irasmstruct-1].name,ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].name); - ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].crc=GetCRC(ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].fullname); - } - ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].size=ae->rasmstruct[ae->irasmstruct-1].size-ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].offset; - ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].fullname=MemMalloc(newlen+strlen(ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].name)); - sprintf(ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].fullname,"%s.%s",ae->rasmstruct[ae->irasmstruct-1].name,ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].name); - ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].crc=GetCRC(ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].fullname); - - /* unwrap data capture */ - if (ae->as80==1) {/* not for UZ80 */ - instruction[ICRC_DEFB].makemnemo=_DEFB_as80;instruction[ICRC_DB].makemnemo=_DEFB_as80; - instruction[ICRC_DEFW].makemnemo=_DEFW_as80;instruction[ICRC_DW].makemnemo=_DEFW_as80; - instruction[ICRC_DEFI].makemnemo=_DEFI_as80; - } else { - instruction[ICRC_DEFB].makemnemo=_DEFB;instruction[ICRC_DB].makemnemo=_DEFB; - instruction[ICRC_DEFW].makemnemo=_DEFW;instruction[ICRC_DW].makemnemo=_DEFW; - instruction[ICRC_DEFI].makemnemo=_DEFI; - } - instruction[ICRC_DEFR].makemnemo=_DEFR;instruction[ICRC_DR].makemnemo=_DEFR; - instruction[ICRC_DEFS].makemnemo=_DEFS;instruction[ICRC_DS].makemnemo=_DEFS; - - /* like there was no byte */ - ae->outputadr=ae->backup_outputadr; - ae->codeadr=ae->backup_codeadr; - - ___org_close(ae); - ___org_new(ae,0); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ENDSTRUCT encountered outside STRUCT declaration\n"); - } - } -} - -void __MEMSPACE(struct s_assenv *ae) { - if (ae->wl[ae->idx].t) { - ___new_memory_space(ae); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"MEMSPACE directive does not need parameter\n"); - } -} - -int (*_internal_getsample)(unsigned char *data, int *idx); -#undef FUNC -#define FUNC "_internal_AudioGetSampleValue" - -int __internal_getsample8(unsigned char *data, int *idx) { - unsigned char v; - v=data[*idx]-128;*idx=*idx+1;return v; -} -int __internal_getsample16little(unsigned char *data, int *idx) { - int cursample; - cursample=data[*idx+1]-0x80;*idx=*idx+2; - return cursample; -} -int __internal_getsample24little(unsigned char *data, int *idx) { - int cursample; - cursample=data[*idx+2-0x80];*idx=*idx+3; - return cursample; -} -/* big-endian */ -int __internal_getsample16big(unsigned char *data, int *idx) { - int cursample; - cursample=data[*idx]-0x80;*idx=*idx+2; - return cursample; -} -int __internal_getsample24big(unsigned char *data, int *idx) { - int cursample; - cursample=data[*idx]-0x80;*idx=*idx+3; - return cursample; -} -/* float & endian shit */ -int _isLittleEndian() /* from lz4.h */ -{ - const union { U32 u; BYTE c[4]; } one = { 1 }; - return one.c[0]; -} - -unsigned char * __internal_floatinversion(unsigned char *data) { - static unsigned char bswap[4]; - bswap[0]=data[3]; - bswap[1]=data[2]; - bswap[2]=data[1]; - bswap[3]=data[0]; - return bswap; -} - -int __internal_getsample32bigbig(unsigned char *data, int *idx) { - float fsample; - int cursample; - fsample=*((float*)(data+*idx)); - *idx=*idx+4; - cursample=(floor)((fsample+1.0)*127.5+0.5); - return cursample; -} -int __internal_getsample32biglittle(unsigned char *data, int *idx) { - float fsample; - int cursample; - fsample=*((float*)(__internal_floatinversion(data+*idx))); - *idx=*idx+4; - cursample=(floor)((fsample+1.0)*127.5+0.5); - return cursample; -} - -#define __internal_getsample32littlelittle __internal_getsample32bigbig -#define __internal_getsample32littlebig __internal_getsample32biglittle - - -void _AudioLoadSample(struct s_assenv *ae, unsigned char *data, int filesize, enum e_audio_sample_type sample_type, float normalize) -{ - #undef FUNC - #define FUNC "AudioLoadSample" - - struct s_wav_header *wav_header; - int i,j,n,idx,controlsize; - int nbchannel,bitspersample,nbsample; - int bigendian=0,cursample; - double accumulator; - unsigned char samplevalue=0, sampleprevious=0; - int samplerepeat=0,ipause; - - unsigned char *subchunk; - int subchunksize; - - if (filesizewl[ae->idx].l,"WAV import - this file is too small to be a valid WAV!\n"); - return; - } - - wav_header=(struct s_wav_header *)data; - -#if TRACE_HEXBIN -printf("AudioLoadSample filesize=%d st=%d normalize=%.2lf\n",filesize,sample_type,normalize); -#endif - if (strncmp(wav_header->ChunkID,"RIFF",4)) { - if (strncmp(wav_header->ChunkID,"RIFX",4)) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WAV import - unsupported audio sample type (chunkid must be 'RIFF' or 'RIFX')\n"); - return; - } else { - bigendian=1; - } - } - if (strncmp(wav_header->Format,"WAVE",4)) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"[%s:%d] WAV import - unsupported audio sample type (format must be 'WAVE')\n"); - return; - } - controlsize=wav_header->SubChunk1Size[0]+wav_header->SubChunk1Size[1]*256+wav_header->SubChunk1Size[2]*65536+wav_header->SubChunk1Size[3]*256*65536; - if (controlsize!=16) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WAV import - invalid wav chunk size (subchunk1 control)\n"); - return; - } - if (strncmp(wav_header->SubChunk1ID,"fmt",3)) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WAV import - unsupported audio sample type (subchunk1id must be 'fmt')\n"); - return; - } - -#if TRACE_HEXBIN -printf("AudioLoadSample getsubchunk\n"); -#endif - subchunk=(unsigned char *)&wav_header->SubChunk2ID; - while (strncmp(subchunk,"data",4)) { - subchunksize=8+subchunk[4]+subchunk[5]*256+subchunk[6]*65536+subchunk[7]*256*65536; - if (subchunksize>=filesize) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WAV import - data subchunk not found\n"); - return; - } - subchunk+=subchunksize; - } - subchunksize=subchunk[4]+subchunk[5]*256+subchunk[6]*65536+subchunk[7]*256*65536; - controlsize=subchunksize; - - nbchannel=wav_header->NumChannels[0]+wav_header->NumChannels[1]*256; - if (nbchannel<1) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WAV import - invalid number of audio channel\n"); - return; - } - bitspersample=wav_header->BitsPerSample[0]+wav_header->BitsPerSample[1]*256; -#if TRACE_HEXBIN -printf("AudioLoadSample bitpersample=%d\n",bitspersample); -#endif - switch (bitspersample) { - case 8:_internal_getsample=__internal_getsample8;break; - case 16:if (!bigendian) _internal_getsample=__internal_getsample16little; else _internal_getsample=__internal_getsample16big;break; - case 24:if (!bigendian) _internal_getsample=__internal_getsample24little; else _internal_getsample=__internal_getsample24big;break; - case 32:if (!bigendian) { - if (_isLittleEndian()) { - _internal_getsample=__internal_getsample32littlelittle; - } else { - _internal_getsample=__internal_getsample32littlebig; - } - } else { - if (_isLittleEndian()) { - _internal_getsample=__internal_getsample32biglittle; - } else { - _internal_getsample=__internal_getsample32bigbig; - } - } - break; - default: - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WAV import - unsupported bits per sample (%d)\n",bitspersample); - return; - } - - nbsample=controlsize/nbchannel/(bitspersample/8); - if (controlsize+sizeof(struct s_wav_header)>filesize) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WAV import - cannot read %d byte%s of audio whereas the file is %d bytes big!\n",controlsize,controlsize>1?"s":"",filesize); - return; - } - -#if TRACE_HEXBIN -printf("nbsample=%d (sze=%d,chn=%d,bps=%d) st=%c\n",nbsample,controlsize,nbchannel,bitspersample,sample_type); -#endif - - idx=subchunk-data; - switch (sample_type) { - default: - case AUDIOSAMPLE_SMP: - for (i=0;ipsgfine[cursample]; - - /* output */ - ___output(ae,samplevalue); - } - break; - case AUDIOSAMPLE_SM2: - /* +1 pour éviter le segfault */ - for (i=0;ipsgfine[cursample]); - } - - /* output */ - ___output(ae,samplevalue); - } - break; - case AUDIOSAMPLE_SM4: - /*** - SM4 format has two bits - bits -> PSG value - 00 -> 0 - 01 -> 13 - 10 -> 14 - 11 -> 15 - ***/ - /* +3 pour éviter le segfault */ - for (i=0;ipsgtab[cursample]>>2); - } - /* output */ - ___output(ae,samplevalue); - } - break; - case AUDIOSAMPLE_DMA: - sampleprevious=255; - for (i=0;ipsgtab[cursample]; - - if (samplevalue==sampleprevious) { - samplerepeat++; - } else { - if (!samplerepeat) { - /* DMA output */ - ___output(ae,sampleprevious); - ___output(ae,0x0A); /* volume canal C */ - } else { - /* DMA pause */ - ___output(ae,sampleprevious); - ___output(ae,0x0A); /* volume canal C */ - while (samplerepeat) { - ipause=samplerepeat<4096?samplerepeat:4095; - ___output(ae,ipause&0xFF); - ___output(ae,0x10 | ((ipause>>8) &0xF)); /* pause */ - - samplerepeat-=4096; - if (samplerepeat<0) samplerepeat=0; - } - } - sampleprevious=samplevalue; - } - } - if (samplerepeat) { - /* DMA pause */ - ___output(ae,sampleprevious); - ___output(ae,0x0A); /* volume canal C */ - while (samplerepeat) { - ipause=samplerepeat<4096?samplerepeat:4095; - ___output(ae,ipause&0xFF); - ___output(ae,0x10 | ((ipause>>8) &0xF)); /* pause */ - - samplerepeat-=4096; - if (samplerepeat<0) samplerepeat=0; - } - } - ___output(ae,0); - ___output(ae,0x0A); /* volume canal C */ - ___output(ae,0x20); - ___output(ae,0x40); /* stop or reloop? */ - break; - } -} - -/* - meta fonction qui gère le INCBIN standard plus les variantes SMP et DMA -*/ -void __HEXBIN(struct s_assenv *ae) { - int hbinidx,overwritecheck=1,crc; - struct s_expr_dico *rvar; - unsigned int idx; - int size=0,offset=0; - float amplification=1.0; - int deload=0; - int vtiles=0,remap=0,revert=0; - int itiles=0,tilex; - - if (!ae->wl[ae->idx].t) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,1); - hbinidx=RoundComputeExpressionCore(ae,ae->wl[ae->idx+1].w,ae->codeadr,0); - if (hbinidx>ae->ih) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"internal error with binary file import (index out of bounds)\n"); - return; - } -#if TRACE_HEXBIN -printf("Hexbin idx=[%s] filename=[%s]\n",ae->wl[ae->idx+1].w,ae->hexbin[hbinidx].filename); -#endif - - if (!ae->wl[ae->idx+1].t) { - if (strcmp("DSK",ae->wl[ae->idx+2].w)==0) { - /* import binary from DSK */ - } else if (strchr("SD",ae->wl[ae->idx+2].w[0]) && ae->wl[ae->idx+2].w[1]=='M' && - strchr("P24A",ae->wl[ae->idx+2].w[2]) && !ae->wl[ae->idx+2].w[3]) { - /* SMP,SM2,SM4,DMA */ - -#if TRACE_HEXBIN -printf("Hexbin -> %s\n",ae->wl[ae->idx+2].w); -#endif - if (!ae->wl[ae->idx+2].t) { - amplification=ComputeExpressionCore(ae,ae->wl[ae->idx+3].w,ae->codeadr,0); -#if TRACE_HEXBIN -printf("sample amplification=%.2lf\n",amplification); -#endif - } - - switch (ae->wl[ae->idx+2].w[2]) { - case 'P':_AudioLoadSample(ae,ae->hexbin[hbinidx].data,ae->hexbin[hbinidx].datalen, AUDIOSAMPLE_SMP,amplification);break; - case '2':_AudioLoadSample(ae,ae->hexbin[hbinidx].data,ae->hexbin[hbinidx].datalen, AUDIOSAMPLE_SM2,amplification);break; - case '4':_AudioLoadSample(ae,ae->hexbin[hbinidx].data,ae->hexbin[hbinidx].datalen, AUDIOSAMPLE_SM4,amplification);break; - case 'A':_AudioLoadSample(ae,ae->hexbin[hbinidx].data,ae->hexbin[hbinidx].datalen, AUDIOSAMPLE_DMA,amplification);break; - default:printf("warning remover\n");break; - } - ae->idx+=2; - return; - } else { - /* legacy binary file */ -#if TRACE_HEXBIN -printf("Hexbin legacy datalen=%d\n",ae->hexbin[hbinidx].datalen); -#endif - if (strcmp("REVERT",ae->wl[ae->idx+2].w)==0) { - /* revert data */ - if (!ae->wl[ae->idx+2].t) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN REVERT does not need extra parameters\n"); - } -#if TRACE_HEXBIN -printf(" -> REVERT loading\n"); -#endif - revert=1; - offset=size=0; // full file - ae->idx++; - - } else if (strcmp("REMAP",ae->wl[ae->idx+2].w)==0) { - /* reorder tiles data */ - if (!ae->wl[ae->idx+2].t) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+3].w,1); - remap=RoundComputeExpressionCore(ae,ae->wl[ae->idx+3].w,ae->codeadr,0); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN REMAP need a number of columns for reordering\n"); - } -#if TRACE_HEXBIN -printf(" -> REMAP loading\n"); -#endif - offset=size=0; // full file - ae->idx+=2; - - } else if (strcmp("ITILES",ae->wl[ae->idx+2].w)==0) { - /*** entrelace les tiles, besoin de hauteur et largeur de la tile ***/ - if (!ae->wl[ae->idx+2].t) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+3].w,1); - tilex=RoundComputeExpressionCore(ae,ae->wl[ae->idx+3].w,ae->codeadr,0); - itiles=1; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"usage is INCBIN'file',ITILES,width\n"); - } -#if TRACE_HEXBIN -printf(" -> ITILES loading\n"); -#endif - offset=size=0; // full file - ae->idx+=2; - } else if (strcmp("VTILES",ae->wl[ae->idx+2].w)==0) { - /* import and reorder tiles */ - if (!ae->wl[ae->idx+2].t) { - ExpressionFastTranslate(ae,&ae->wl[ae->idx+3].w,1); - vtiles=RoundComputeExpressionCore(ae,ae->wl[ae->idx+3].w,ae->codeadr,0); - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN VTILES need a number of lines for reordering\n"); - } -#if TRACE_HEXBIN -printf(" -> VTILES loading\n"); -#endif - offset=size=0; // full file - ae->idx+=2; - } else { - char *expwrk; - - expwrk=TxtStrDup(ae->wl[ae->idx+2].w); - ExpressionFastTranslate(ae,&expwrk,1); - offset=RoundComputeExpressionCore(ae,expwrk,ae->codeadr,0); - MemFree(expwrk); -#if TRACE_HEXBIN - printf("offset=%d\n",offset); -#endif - if (!ae->wl[ae->idx+2].t) { - if (ae->wl[ae->idx+3].w[0]) { - expwrk=TxtStrDup(ae->wl[ae->idx+3].w); - ExpressionFastTranslate(ae,&expwrk,1); - size=RoundComputeExpressionCore(ae,expwrk,ae->codeadr,0); - MemFree(expwrk); - } else { - size=0; - } -#if TRACE_HEXBIN - printf("size=%d\n",size); -#endif - if (size<-65535 || size>65536) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN invalid size\n"); - } - if (!ae->wl[ae->idx+3].t) { - if (ae->wl[ae->idx+4].w[0]) { - expwrk=TxtStrDup(ae->wl[ae->idx+4].w); - ExpressionFastTranslate(ae,&expwrk,1); - offset+=65536*RoundComputeExpressionCore(ae,expwrk,ae->codeadr,0); - MemFree(expwrk); - } - if (!ae->wl[ae->idx+4].t) { - if (strcmp(ae->wl[ae->idx+5].w,"OFF")==0) { - overwritecheck=0; - } else if (strcmp(ae->wl[ae->idx+5].w,"ON")==0) { - overwritecheck=1; -#if TRACE_HEXBIN - printf("mode OVERWRITE\n"); -#endif - } else if (ae->wl[ae->idx+5].w[0]) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN invalid overwrite value. Must be 'OFF' or 'ON'\n"); - } - if (!ae->wl[ae->idx+5].t) { - /* copy raw len to a (new) variable */ - crc=GetCRC(ae->wl[ae->idx+6].w); - if ((rvar=SearchDico(ae,ae->wl[ae->idx+6].w,crc))!=NULL) { - rvar->v=ae->hexbin[hbinidx].rawlen; - } else { - /* mais ne peut être un label ou un alias */ - ExpressionSetDicoVar(ae,ae->wl[ae->idx+6].w,ae->hexbin[hbinidx].rawlen); - } - ae->idx+=6; - } else { - ae->idx+=5; - } - } else { - ae->idx+=4; - } - } else { - ae->idx+=3; - } - } else { - ae->idx+=2; - } - } - } - } else { - ae->idx++; - } - - /* preprocessor cannot manage variables so here is the delayed load */ - if (ae->hexbin[hbinidx].datalen<0) { - struct s_hexbin *curhexbin; - char *newfilename; - int lm,touched; - unsigned char *newdata=NULL; - -#if TRACE_HEXBIN -printf("Hexbin -> as only the assembler know how to deal with var,\n"); -printf("we look for tags in the name of a file which were not found\n"); -#endif - curhexbin=&ae->hexbin[hbinidx]; - - newfilename=TxtStrDup(curhexbin->filename); - - /* need to upper case tags */ - for (lm=touched=0;newfilename[lm];lm++) { - if (newfilename[lm]=='{') touched++; else if (newfilename[lm]=='}') touched--; else if (touched) newfilename[lm]=toupper(newfilename[lm]); - } - /* on essaie d'interpréter le nom du fichier en dynamique */ - newfilename=TranslateTag(ae,newfilename,&touched,1,E_TAGOPTION_REMOVESPACE); - /* load */ - if (FileExists(newfilename)) { -#if TRACE_HEXBIN -printf("Hexbin -> surprise! we found the file!\n"); -#endif - curhexbin->rawlen=curhexbin->datalen=FileGetSize(newfilename); - curhexbin->data=MemMalloc(curhexbin->datalen*1.3+10); - if (FileReadBinary(newfilename,(char*)curhexbin->data,curhexbin->datalen)!=curhexbin->datalen) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"read error on file [%s]\n",newfilename); - return; - } - FileReadBinaryClose(newfilename); - - switch (curhexbin->crunch) { - #ifndef NO_3RD_PARTIES - case 4: - newdata=LZ4_crunch(curhexbin->data,curhexbin->datalen,&curhexbin->datalen); - MemFree(curhexbin->data); - curhexbin->data=newdata; - #if TRACE_PREPRO - rasm_printf(ae,KVERBOSE"crunched with LZ4 into %d byte(s)\n",curhexbin->datalen); - #endif - break; - case 7: - { - size_t slzlen; - newdata=ZX7_compress(optimize(curhexbin->data, curhexbin->datalen), curhexbin->data, curhexbin->datalen, &slzlen); - curhexbin->datalen=slzlen; - MemFree(curhexbin->data); - curhexbin->data=newdata; - #if TRACE_PREPRO - rasm_printf(ae,KVERBOSE"crunched with ZX7 into %d byte(s)\n",curhexbin->datalen); - #endif - } - break; - case 8: - rasm_printf(ae,KWARNING"Exomizer is crunching %.1fkb this may take a while, be patient...\n",curhexbin->datalen/1024.0); - newdata=Exomizer_crunch(curhexbin->data,curhexbin->datalen,&curhexbin->datalen); - MemFree(curhexbin->data); - curhexbin->data=newdata; - #if TRACE_PREPRO - rasm_printf(ae,KVERBOSE"crunched with Exomizer into %d byte(s)\n",curhexbin->datalen); - #endif - break; - #endif - case 48: - newdata=LZ48_crunch(curhexbin->data,curhexbin->datalen,&curhexbin->datalen); - MemFree(curhexbin->data); - curhexbin->data=newdata; - #if TRACE_PREPRO - rasm_printf(ae,KVERBOSE"crunched with LZ48 into %d byte(s)\n",curhexbin->datalen); - #endif - break; - case 49: - newdata=LZ49_crunch(curhexbin->data,curhexbin->datalen,&curhexbin->datalen); - MemFree(curhexbin->data); - curhexbin->data=newdata; - #if TRACE_PREPRO - rasm_printf(ae,KVERBOSE"crunched with LZ49 into %d byte(s)\n",curhexbin->datalen); - #endif - break; - default:break; - } - deload=1; - } else { - /* still not found */ - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"file not found [%s]\n",newfilename); - return; - } - } - - if (ae->hexbin[hbinidx].datalen>0) { - if (hbinidxih && hbinidx>=0) { - if (size<0) { -#if TRACE_HEXBIN -printf("taille négative %d -> conversion en %d\n",size,ae->hexbin[hbinidx].datalen+size); -#endif - size=ae->hexbin[hbinidx].datalen+size; - if (size<1) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN negative size is greater or equal to filesize\n"); - } - } - /* negative offset conversion */ - if (offset<0) { -#if TRACE_HEXBIN -printf("offset négatif %d -> conversion en %d\n",offset,ae->hexbin[hbinidx].datalen+offset); -#endif - offset=ae->hexbin[hbinidx].datalen+offset; - } - if (!size) { - if (!offset) { - size=ae->hexbin[hbinidx].datalen; - } else { - size=ae->hexbin[hbinidx].datalen-offset; - } -#if TRACE_HEXBIN -printf("taille nulle et offset=%d -> conversion en %d\n",offset,size); -#endif - } - if (size>ae->hexbin[hbinidx].datalen) { - rasm_printf(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN size is greater than filesize\n"); - } else { - if (size+offset>ae->hexbin[hbinidx].datalen) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN size+offset is greater than filesize\n"); - } else { - if (revert) { - int p; - p=size-1; - while (p>=0) { - ___output(ae,ae->hexbin[hbinidx].data[p--]); - } - } else if (itiles) { - /* tiles data reordering */ - int tx,ty,it,width; - - if (size % (tilex*8)) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN ITILES cannot reorder tiles %d bytewidth with file of size %d\n",tilex,size); - } else { - it=0; - while (ithexbin[hbinidx].data[it+tx+0*tilex]); - for (tx=tilex-1;tx>=0;tx--) ___output(ae,ae->hexbin[hbinidx].data[it+tx+1*tilex]); - for (tx=0;txhexbin[hbinidx].data[it+tx+3*tilex]); - for (tx=tilex-1;tx>=0;tx--) ___output(ae,ae->hexbin[hbinidx].data[it+tx+2*tilex]); - for (tx=0;txhexbin[hbinidx].data[it+tx+6*tilex]); - for (tx=tilex-1;tx>=0;tx--) ___output(ae,ae->hexbin[hbinidx].data[it+tx+7*tilex]); - for (tx=0;txhexbin[hbinidx].data[it+tx+5*tilex]); - for (tx=tilex-1;tx>=0;tx--) ___output(ae,ae->hexbin[hbinidx].data[it+tx+4*tilex]); - it+=tilex*8; - } - } - } else if (remap) { - /* tiles data reordering */ - int tx,ty,it,width; - - width=size/remap; - - if ((size % remap) || (remap*width>size)) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN REMAP cannot reorder %d columns%s with file of size %d\n",remap,remap>1?"s":"",size); - } else { - for (it=0;ithexbin[hbinidx].data[it+tx*remap]); - } - } - } - - } else if (vtiles) { - /* tiles map reordering */ - int width,tilex,tiley; - - width=size/vtiles; - - if ((size % vtiles) || (vtiles*width>size)) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN VTILES cannot reorder %d line%s with file of size %d\n",vtiles,vtiles>1?"s":"",size); - } else { -#if TRACE_HEXBIN -printf("Hexbin -> re-tiling MAP! width=%d\n",width); -#endif - for (idx=tilex=tiley=0;idxhexbin[hbinidx].data[tilex+tiley*width]); - tiley++; - if (tiley>=vtiles) { - tiley=0; - tilex++; - } - } - } - } else { - /* legacy HEXBIN */ - if (overwritecheck) { - for (idx=offset;idxhexbin[hbinidx].data[idx]); - } - } else { - ___org_close(ae); - ___org_new(ae,0); - for (idx=offset;idxhexbin[hbinidx].data[idx]); - } - /* hack to disable overwrite check */ - ae->orgzone[ae->io-1].nocode=2; - ___org_close(ae); - ___org_new(ae,0); - } - } - } - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INTERNAL - HEXBIN refer to unknown structure\n"); - FreeAssenv(ae); - exit(2); - } - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INTERNAL - HEXBIN need one HEX parameter\n"); - FreeAssenv(ae); - exit(2); - } - - /* generated names must be reloaded! */ - if (deload) { - ae->hexbin[hbinidx].datalen=-1; - MemFree(ae->hexbin[hbinidx].data); - } -} - -/* -save "nom",start,size -> save binary -save "nom",start,size,TAPE -> save tape file -save "nom",start,size,AMSDOS -> save binary with Amsdos header -save "nom",start,size,DSK,"dskname" -> save binary on DSK data format -save "nom",start,size,DSK,"dskname",B -> select face -save "nom",start,size,DSK,B -> current DSK, choose face -save "nom",start,size,DSK -> current DSK, current face -*/ -void __SAVE(struct s_assenv *ae) { - struct s_save cursave={0}; - unsigned int offset=0,size=0; - int ko=1; - - if (!ae->wl[ae->idx].t) { - /* nom de fichier entre quotes ou bien mot clef DSK */ - if (!StringIsQuote(ae->wl[ae->idx+1].w)) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SAVE invalid filename quote\n"); - ko=0; - } else { - if (!ae->wl[ae->idx+1].t) { - if (!ae->wl[ae->idx+2].t && ae->wl[ae->idx+3].t!=2) { - cursave.ibank=ae->activebank; - cursave.ioffset=ae->idx+2; - ExpressionFastTranslate(ae,&ae->wl[ae->idx+2].w,1); // si on utilise des variables ça évite la grouille post traitement... - cursave.isize=ae->idx+3; - ExpressionFastTranslate(ae,&ae->wl[ae->idx+3].w,1); // idem - cursave.iw=ae->idx+1; - cursave.irun=ae->current_run_idx; - if (!ae->wl[ae->idx+3].t) { - if (strcmp(ae->wl[ae->idx+4].w,"TAPE")==0) { - cursave.tape=1; - } else if (strcmp(ae->wl[ae->idx+4].w,"AMSDOS")==0) { - cursave.amsdos=1; - } else if (strcmp(ae->wl[ae->idx+4].w,"HOBETA")==0) { - cursave.hobeta=1; - } else if (strcmp(ae->wl[ae->idx+4].w,"DSK")==0) { -#if TRACE_EDSK - printf("DSK SAVE order [bnk: %d ioff: %d isiz: %d iw=%d [%s] [%s]\n",cursave.ibank,cursave.ioffset,cursave.isize,cursave.iw,ae->wl[ae->idx+2].w,ae->wl[ae->idx+3].w); -#endif - cursave.dsk=1; - if (!ae->wl[ae->idx+4].t) { - cursave.iwdskname=ae->idx+5; - if (!ae->wl[ae->idx+5].t) { - /* face selection - 0 as default */ - switch (ae->wl[ae->idx+6].w[0]) { - case '1': - case 'B': - cursave.face=1; - break; - case '0': - case 'A': - default: - cursave.face=0; - break; - } - } - } else { - if (ae->nbsave && ae->save[ae->nbsave-1].iwdskname!=-1) { - cursave.iwdskname=ae->save[ae->nbsave-1].iwdskname; /* previous DSK */ - cursave.face=ae->save[ae->nbsave-1].face; /* previous face */ - } else { - cursave.iwdskname=-1; - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"cannot autoselect DSK as there was not a previous selection\n"); - } - } - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SAVE 4th parameter must be empty or AMSDOS or DSK\n"); - ko=0; - } - } - ObjectArrayAddDynamicValueConcat((void**)&ae->save,&ae->nbsave,&ae->maxsave,&cursave,sizeof(cursave)); - ko=0; - } - } - } - } - if (ko) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use SAVE 'filename',offset,size[,AMSDOS|DSK[,A|B|'dskname'[,A|B]]]\n"); - } - while (!ae->wl[ae->idx].t) ae->idx++; -} - - -void __MODULE(struct s_assenv *ae) { - if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { - if (StringIsQuote(ae->wl[ae->idx+1].w)) { - if (ae->modulen || ae->module) { - MemFree(ae->module); - } - ae->modulen=strlen(ae->wl[ae->idx+1].w); - ae->module=MemMalloc(ae->modulen); - /* duplicate and remove quotes */ - strcpy(ae->module,ae->wl[ae->idx+1].w+1); - ae->module[--ae->modulen]=0; - } else { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"MODULE directive need one text parameter\n"); - } - ae->idx++; - } else { - if (ae->module) MemFree(ae->module); - ae->module=NULL; - } -} - -void __TIMESTR(struct s_assenv *ae) { - -} - -struct s_asm_keyword instruction[]={ -{"LD",0,_LD}, -{"DEC",0,_DEC}, -{"INC",0,_INC}, -{"ADD",0,_ADD}, -{"SUB",0,_SUB}, -{"OR",0,_OR}, -{"AND",0,_AND}, -{"XOR",0,_XOR}, -{"POP",0,_POP}, -{"PUSH",0,_PUSH}, -{"DJNZ",0,_DJNZ}, -{"JR",0,_JR}, -{"JP",0,_JP}, -{"CALL",0,_CALL}, -{"RET",0,_RET}, -{"EX",0,_EX}, -{"ADC",0,_ADC}, -{"SBC",0,_SBC}, -{"EXA",0,_EXA}, -{"EXX",0,_EXX}, -{"CP",0,_CP}, -{"BIT",0,_BIT}, -{"RES",0,_RES}, -{"SET",0,_SET}, -{"IN",0,_IN}, -{"OUT",0,_OUT}, -{"RLC",0,_RLC}, -{"RRC",0,_RRC}, -{"RL",0,_RL}, -{"RR",0,_RR}, -{"SLA",0,_SLA}, -{"SRA",0,_SRA}, -{"SLL",0,_SLL}, -{"SL1",0,_SLL}, -{"SRL",0,_SRL}, -{"RST",0,_RST}, -{"HALT",0,_HALT}, -{"DI",0,_DI}, -{"EI",0,_EI}, -{"NOP",0,_NOP}, -{"DEFR",0,_DEFR}, -{"DEFB",0,_DEFB}, -{"DEFM",0,_DEFB}, -{"DR",0,_DEFR}, -{"DM",0,_DEFB}, -{"DB",0,_DEFB}, -{"DEFW",0,_DEFW}, -{"DW",0,_DEFW}, -{"DEFS",0,_DEFS}, -{"DS",0,_DEFS}, -{"STR",0,_STR}, -{"LDI",0,_LDI}, -{"LDIR",0,_LDIR}, -{"OUTI",0,_OUTI}, -{"INI",0,_INI}, -{"RLCA",0,_RLCA}, -{"RRCA",0,_RRCA}, -{"NEG",0,_NEG}, -{"RLA",0,_RLA}, -{"RRA",0,_RRA}, -{"RLD",0,_RLD}, -{"RRD",0,_RRD}, -{"DAA",0,_DAA}, -{"CPL",0,_CPL}, -{"SCF",0,_SCF}, -{"LDD",0,_LDD}, -{"LDDR",0,_LDDR}, -{"CCF",0,_CCF}, -{"OUTD",0,_OUTD}, -{"IND",0,_IND}, -{"RETI",0,_RETI}, -{"RETN",0,_RETN}, -{"IM",0,_IM}, -{"DEFI",0,_DEFI}, -{"CPD",0,_CPD}, -{"CPI",0,_CPI}, -{"CPDR",0,_CPDR}, -{"CPIR",0,_CPIR}, -{"OTDR",0,_OTDR}, -{"OTIR",0,_OTIR}, -{"INDR",0,_INDR}, -{"INIR",0,_INIR}, -{"REPEAT",0,__REPEAT}, -{"REND",0,__REND}, -{"ENDREPEAT",0,__REND}, -{"ENDREP",0,__REND}, -{"UNTIL",0,__UNTIL}, -{"ORG",0,__ORG}, -{"PROTECT",0,__PROTECT}, -{"WHILE",0,__WHILE}, -{"WEND",0,__WEND}, -{"HEXBIN",0,__HEXBIN}, -{"ALIGN",0,__ALIGN}, -{"ELSEIF",0,__ELSEIF}, -{"ELSE",0,__ELSE}, -{"IF",0,__IF}, -{"ENDIF",0,__ENDIF}, -{"IFNOT",0,__IFNOT}, -{"IFDEF",0,__IFDEF}, -{"IFNDEF",0,__IFNDEF}, -{"IFUSED",0,__IFUSED}, -{"IFNUSED",0,__IFNUSED}, -{"UNDEF",0,__UNDEF}, -{"CASE",0,__CASE}, -{"BREAK",0,__BREAK}, -{"DEFAULT",0,__DEFAULT}, -{"SWITCH",0,__SWITCH}, -{"ENDSWITCH",0,__ENDSWITCH}, -{"WRITE",0,__WRITE}, -{"CODE",0,__CODE}, -{"NOCODE",0,__NOCODE}, -{"MEMSPACE",0,__MEMSPACE}, -{"MACRO",0,__MACRO}, -{"TICKER",0,__TICKER}, -{"LET",0,__LET}, -{"ASSERT",0,__ASSERT}, -{"CHARSET",0,__CHARSET}, -{"RUN",0,__RUN}, -{"SAVE",0,__SAVE}, -{"BRK",0,__BRK}, -{"NOLIST",0,__NOLIST}, -{"LIST",0,__LIST}, -{"STOP",0,__STOP}, -{"PRINT",0,__PRINT}, -{"FAIL",0,__FAIL}, -{"BREAKPOINT",0,__BREAKPOINT}, -{"BANK",0,__BANK}, -{"BANKSET",0,__BANKSET}, -{"NAMEBANK",0,__NameBANK}, -{"LIMIT",0,__LIMIT}, -{"LZEXO",0,__LZEXO}, -{"LZX7",0,__LZX7}, -{"LZ4",0,__LZ4}, -{"LZ48",0,__LZ48}, -{"LZ49",0,__LZ49}, -{"LZCLOSE",0,__LZCLOSE}, -{"BUILDZX",0,__BUILDZX}, -{"BUILDCPR",0,__BUILDCPR}, -{"BUILDSNA",0,__BUILDSNA}, -{"BUILDROM",0,__BUILDROM}, -{"BUILDTAPE",0,__BUILDTAPE}, -{"SETCPC",0,__SETCPC}, -{"SETCRTC",0,__SETCRTC}, -{"AMSDOS",0,__AMSDOS}, -{"OTD",0,_OUTD}, -{"OTI",0,_OUTI}, -{"SHL",0,_SLA}, -{"SHR",0,_SRL}, -{"STRUCT",0,__STRUCT}, -{"ENDSTRUCT",0,__ENDSTRUCT}, -{"ENDS",0,__ENDSTRUCT}, -{"NOEXPORT",0,__NOEXPORT}, -{"ENOEXPORT",0,__ENOEXPORT}, -{"",0,NULL} -}; - -int Assemble(struct s_assenv *ae, unsigned char **dataout, int *lenout, struct s_rasm_info **debug) -{ - #undef FUNC - #define FUNC "Assemble" - - unsigned char *AmsdosHeader; - struct s_expression curexp={0}; - struct s_wordlist *wordlist; - struct s_expr_dico curdico={0}; - struct s_label *curlabel; - int icrc,curcrc,i,j,k; - unsigned char *lzdata=NULL; - int lzlen,lzshift,input_size; - size_t slzlen; - unsigned char *input_data; - struct s_orgzone orgzone={0}; - int iorgzone,ibank,offset,endoffset; - int il,maxrom; - char *TMP_filename=NULL; - int minmem=65536,maxmem=0,lzmove; - char symbol_line[1024]; - int ifast,executed; - /* debug */ - int curii,inhibe; - int ok; - - rasm_printf(ae,KAYGREEN"Assembling\n"); -#if TRACE_ASSEMBLE -printf("assembling\n"); -#endif -#if TRACE_GENERALE -printf("*** assembling ***\n"); -#endif - - ae->retdebug=debug; - - srand((unsigned)time(0)); - - wordlist=ae->wl; - ae->wl=wordlist; - /* start outside crunched section */ - ae->lz=-1; - - /* default orgzone */ - orgzone.ibank=BANK_MAX_NUMBER; - ObjectArrayAddDynamicValueConcat((void**)&ae->orgzone,&ae->io,&ae->mo,&orgzone,sizeof(orgzone)); - ___output=___internal_output; - /* init des automates */ - InitAutomate(ae->AutomateHexa,AutomateHexaDefinition); - InitAutomate(ae->AutomateDigit,AutomateDigitDefinition); - InitAutomate(ae->AutomateValidLabel,AutomateValidLabelDefinition); - InitAutomate(ae->AutomateValidLabelFirst,AutomateValidLabelFirstDefinition); - InitAutomate(ae->AutomateExpressionValidCharExtended,AutomateExpressionValidCharExtendedDefinition); - InitAutomate(ae->AutomateExpressionValidCharFirst,AutomateExpressionValidCharFirstDefinition); - InitAutomate(ae->AutomateExpressionValidChar,AutomateExpressionValidCharDefinition); - ae->AutomateExpressionDecision['<']='<'; - ae->AutomateExpressionDecision['>']='>'; - ae->AutomateExpressionDecision['=']='='; - ae->AutomateExpressionDecision['!']='!'; - ae->AutomateExpressionDecision[0]='E'; - /* gestion d'alias */ - ae->AutomateExpressionDecision['~']='~'; - /* set operator precedence */ - if (!ae->maxam) { - for (i=0;i<256;i++) { - switch (i) { - /* priority 0 */ - case '(':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_OPEN;ae->AutomateElement[i].priority=0;break; - case ')':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_CLOSE;ae->AutomateElement[i].priority=0;break; - /* priority 1 */ - case 'b':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_NOT;ae->AutomateElement[i].priority=1;break; - /* priority 2 */ - case '*':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_MUL;ae->AutomateElement[i].priority=2;break; - case '/':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_DIV;ae->AutomateElement[i].priority=2;break; - case 'm':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_MOD;ae->AutomateElement[i].priority=2;break; - /* priority 3 */ - case '+':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_ADD;ae->AutomateElement[i].priority=3;break; - case '-':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_SUB;ae->AutomateElement[i].priority=3;break; - /* priority 4 */ - case '[':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_SHL;ae->AutomateElement[i].priority=4;break; - case ']':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_SHR;ae->AutomateElement[i].priority=4;break; - /* priority 5 */ - case 'l':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_LOWER;ae->AutomateElement[i].priority=5;break; - case 'g':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_GREATER;ae->AutomateElement[i].priority=5;break; - case 'e':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_EQUAL;ae->AutomateElement[i].priority=5;break; - case 'n':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_NOTEQUAL;ae->AutomateElement[i].priority=5;break; - case 'k':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_LOWEREQ;ae->AutomateElement[i].priority=5;break; - case 'h':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_GREATEREQ;ae->AutomateElement[i].priority=5;break; - /* priority 6 */ - case '&':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_AND;ae->AutomateElement[i].priority=6;break; - /* priority 7 */ - case '^':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_XOR;ae->AutomateElement[i].priority=7;break; - /* priority 8 */ - case '|':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_OR;ae->AutomateElement[i].priority=8;break; - /* priority 9 */ - case 'a':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_BAND;ae->AutomateElement[i].priority=9;break; - /* priority 10 */ - case 'o':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_BOR;ae->AutomateElement[i].priority=10;break; - default:ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_END; - } - } - } else { - for (i=0;i<256;i++) { - switch (i) { - /* priority 0 */ - case '(':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_OPEN;ae->AutomateElement[i].priority=0;break; - case ')':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_CLOSE;ae->AutomateElement[i].priority=0;break; - /* priority 0.5 */ - case 'b':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_NOT;ae->AutomateElement[i].priority=128;break; - /* priority 1 */ - case '*':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_MUL;ae->AutomateElement[i].priority=464;break; - case '/':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_DIV;ae->AutomateElement[i].priority=464;break; - case 'm':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_MOD;ae->AutomateElement[i].priority=464;break; - case '+':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_ADD;ae->AutomateElement[i].priority=464;break; - case '-':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_SUB;ae->AutomateElement[i].priority=464;break; - case '[':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_SHL;ae->AutomateElement[i].priority=464;break; - case ']':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_SHR;ae->AutomateElement[i].priority=464;break; - case '&':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_AND;ae->AutomateElement[i].priority=464;break; - case '^':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_XOR;ae->AutomateElement[i].priority=464;break; - case '|':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_OR;ae->AutomateElement[i].priority=464;break; - /* priority 2 */ - case 'l':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_LOWER;ae->AutomateElement[i].priority=664;break; - case 'g':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_GREATER;ae->AutomateElement[i].priority=664;break; - case 'e':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_EQUAL;ae->AutomateElement[i].priority=664;break; - case 'n':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_NOTEQUAL;ae->AutomateElement[i].priority=664;break; - case 'k':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_LOWEREQ;ae->AutomateElement[i].priority=664;break; - case 'h':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_GREATEREQ;ae->AutomateElement[i].priority=664;break; - /* priority 3 */ - case 'a':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_BAND;ae->AutomateElement[i].priority=6128;break; - case 'o':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_BOR;ae->AutomateElement[i].priority=6128;break; - default:ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_END; - } - } - } - - /* psg conversion */ - for (i=j=0;i<100;i++) ae->psgtab[j++]=0; - for (i=0;i<49;i++) ae->psgtab[j++]=13; - for (i=0;i<35;i++) ae->psgtab[j++]=14; - for (i=0;i<72;i++) ae->psgtab[j++]=15; - if (j!=256) { - rasm_printf(ae,"Internal error with PSG conversion table\n"); - exit(-44); - } - for (i=j=0;i<1;i++) ae->psgfine[j++]=0; - for (i=0;i<1;i++) ae->psgfine[j++]=1; - for (i=0;i<1;i++) ae->psgfine[j++]=2; - for (i=0;i<2;i++) ae->psgfine[j++]=3; - for (i=0;i<2;i++) ae->psgfine[j++]=4; - for (i=0;i<2;i++) ae->psgfine[j++]=5; - for (i=0;i<3;i++) ae->psgfine[j++]=6; - for (i=0;i<4;i++) ae->psgfine[j++]=7; - for (i=0;i<7;i++) ae->psgfine[j++]=8; - for (i=0;i<9;i++) ae->psgfine[j++]=9; - for (i=0;i<13;i++) ae->psgfine[j++]=10; - for (i=0;i<19;i++) ae->psgfine[j++]=11; - for (i=0;i<27;i++) ae->psgfine[j++]=12; - for (i=0;i<37;i++) ae->psgfine[j++]=13; - for (i=0;i<53;i++) ae->psgfine[j++]=14; - for (i=0;i<75;i++) ae->psgfine[j++]=15; - if (j!=256) { - rasm_printf(ae,"Internal error with PSG conversion table\n"); - exit(-44); - } - /* default var */ - ae->autorise_export=1; - ExpressionSetDicoVar(ae,"PI",3.1415926545); - ExpressionSetDicoVar(ae,"ASSEMBLER_RASM",1); - - /* add a fictive expression to simplify test when parsing expressions */ - ObjectArrayAddDynamicValueConcat((void **)&ae->expression,&ae->ie,&ae->me,&curexp,sizeof(curexp)); - - /* compute CRC for keywords and directives */ - for (icrc=0;instruction[icrc].mnemo[0];icrc++) instruction[icrc].crc=GetCRC(instruction[icrc].mnemo); - for (icrc=0;math_keyword[icrc].mnemo[0];icrc++) math_keyword[icrc].crc=GetCRC(math_keyword[icrc].mnemo); - - if (ae->as80==1) { /* not for UZ80 */ - for (icrc=0;instruction[icrc].mnemo[0];icrc++) { - if (strcmp(instruction[icrc].mnemo,"DEFB")==0 || strcmp(instruction[icrc].mnemo,"DB")==0) { - instruction[icrc].makemnemo=_DEFB_as80; - } else if (strcmp(instruction[icrc].mnemo,"DEFW")==0 || strcmp(instruction[icrc].mnemo,"DW")==0) { - instruction[icrc].makemnemo=_DEFW_as80; - } else if (strcmp(instruction[icrc].mnemo,"DEFI")==0) { - instruction[icrc].makemnemo=_DEFI_as80; - } - } - } - - for (icrc=0;instruction[icrc].mnemo[0];icrc++) { - /* get indexes for DEF instructions */ - if (strcmp(instruction[icrc].mnemo,"DEFB")==0) { - ICRC_DEFB=icrc; - } else if (strcmp(instruction[icrc].mnemo,"DB")==0) { - ICRC_DB=icrc; - } else if (strcmp(instruction[icrc].mnemo,"DEFW")==0) { - ICRC_DEFW=icrc; - } else if (strcmp(instruction[icrc].mnemo,"DW")==0) { - ICRC_DW=icrc; - } else if (strcmp(instruction[icrc].mnemo,"DEFR")==0) { - ICRC_DEFR=icrc; - } else if (strcmp(instruction[icrc].mnemo,"DR")==0) { - ICRC_DR=icrc; - } else if (strcmp(instruction[icrc].mnemo,"DEFS")==0) { - ICRC_DEFS=icrc; - } else if (strcmp(instruction[icrc].mnemo,"DS")==0) { - ICRC_DS=icrc; - } else if (strcmp(instruction[icrc].mnemo,"DEFI")==0) { - ICRC_DEFI=icrc; - } - } - - /* Execution des mots clefs */ - /********************************************************** - A S S E M B L I N G M A I N L O O P - **********************************************************/ -#if TRACE_ASSEMBLE -printf("init ok\n"); -#endif -#if TRACE_GENERALE -printf("-loop\n"); -#endif - - ae->idx=1; - while (wordlist[ae->idx].t!=2) { - curcrc=GetCRC(wordlist[ae->idx].w); - /********************* - d e b u g i n f o - *********************/ - #if TRACE_ASSEMBLE - { - int iiii=0; - printf(KVERBOSE"%d [%s] L%d [%s]e=%d ",ae->idx,ae->filename[wordlist[ae->idx].ifile],wordlist[ae->idx].l,wordlist[ae->idx].w,wordlist[ae->idx].e); - while (!wordlist[ae->idx+iiii++].t) rasm_printf(ae," [%s]e=%d ",wordlist[ae->idx+iiii].w,wordlist[ae->idx+iiii].e); - - for (iiii=0;iiiiimacropos;iiii++) { - printf("M[%d] s=%d e=%d ",iiii,ae->macropos[iiii].start,ae->macropos[iiii].end); - } - printf("\n"); - } - #endif - - /******************************************************************** - c o n d i t i o n n a l a s s e m b l y m a n a g e m e n t - ********************************************************************/ - if (ae->ii || ae->isw) { - /* inhibition of if/endif */ - for (inhibe=curii=0;curiiii;curii++) { - if (!ae->ifthen[curii].v || ae->ifthen[curii].v==-1) { - inhibe=1; - break; - } - } - /* when inhibited we are looking only for a IF/IFDEF/IFNOT/IFNDEF/ELSE/ELSEIF/ENDIF or SWITCH/CASE/DEFAULT/ENDSWITCH */ - if (inhibe) { - /* this section does NOT need to be agressively optimized !!! */ - if (curcrc==CRC_ELSEIF && strcmp(wordlist[ae->idx].w,"ELSEIF")==0) { - /* true IF needs to be done ONLY on the active level */ - if (curii==ae->ii-1) __ELSEIF(ae); else __ELSEIF_light(ae); - } else if (curcrc==CRC_ELSE && strcmp(wordlist[ae->idx].w,"ELSE")==0) { - __ELSE(ae); - } else if (curcrc==CRC_ENDIF && strcmp(wordlist[ae->idx].w,"ENDIF")==0) { - __ENDIF(ae); - } else if (curcrc==CRC_IF && strcmp(wordlist[ae->idx].w,"IF")==0) { - /* as we are inhibited we do not have to truly compute IF */ - __IF_light(ae); - } else if (curcrc==CRC_IFDEF && strcmp(wordlist[ae->idx].w,"IFDEF")==0) { - __IFDEF_light(ae); - } else if (curcrc==CRC_IFNOT && strcmp(wordlist[ae->idx].w,"IFNOT")==0) { - __IFNOT_light(ae); - } else if (curcrc==CRC_IFUSED && strcmp(wordlist[ae->idx].w,"IFUSED")==0) { - __IFUSED_light(ae); - } else if (curcrc==CRC_IFNUSED && strcmp(wordlist[ae->idx].w,"IFNUSED")==0) { - __IFNUSED_light(ae); - } else if (curcrc==CRC_IFNDEF && strcmp(wordlist[ae->idx].w,"IFNDEF")==0) { - __IFNDEF_light(ae); - } else if (curcrc==CRC_SWITCH && strcmp(wordlist[ae->idx].w,"SWITCH")==0) { - __SWITCH_light(ae); - } else if (curcrc==CRC_CASE && strcmp(wordlist[ae->idx].w,"CASE")==0) { - __CASE_light(ae); - } else if (curcrc==CRC_ENDSWITCH && strcmp(wordlist[ae->idx].w,"ENDSWITCH")==0) { - __ENDSWITCH(ae); - } else if (curcrc==CRC_BREAK && strcmp(wordlist[ae->idx].w,"BREAK")==0) { - __BREAK_light(ae); - } else if (curcrc==CRC_DEFAULT && strcmp(wordlist[ae->idx].w,"DEFAULT")==0) { - __DEFAULT_light(ae); - } - while (wordlist[ae->idx].t==0) ae->idx++; - ae->idx++; - continue; - } else { - /* inhibition of switch/case */ - for (curii=0;curiiisw;curii++) { - if (!ae->switchcase[curii].execute) { - inhibe=2; - break; - } - } - if (inhibe) { - /* this section does NOT need to be agressively optimized !!! */ - if (curcrc==CRC_CASE && strcmp(wordlist[ae->idx].w,"CASE")==0) { - __CASE(ae); - } else if (curcrc==CRC_ENDSWITCH && strcmp(wordlist[ae->idx].w,"ENDSWITCH")==0) { - __ENDSWITCH(ae); - } else if (curcrc==CRC_IF && strcmp(wordlist[ae->idx].w,"IF")==0) { - /* as we are inhibited we do not have to truly compute IF */ - __IF_light(ae); - } else if (curcrc==CRC_IFDEF && strcmp(wordlist[ae->idx].w,"IFDEF")==0) { - __IFDEF(ae); - } else if (curcrc==CRC_IFNOT && strcmp(wordlist[ae->idx].w,"IFNOT")==0) { - __IFNOT(ae); - } else if (curcrc==CRC_ELSE && strcmp(wordlist[ae->idx].w,"ELSE")==0) { - __ELSE(ae); - } else if (curcrc==CRC_ENDIF && strcmp(wordlist[ae->idx].w,"ENDIF")==0) { - __ENDIF(ae); - } else if (curcrc==CRC_ELSEIF && strcmp(wordlist[ae->idx].w,"ELSEIF")==0) { - __ELSEIF(ae); - } else if (curcrc==CRC_IFUSED && strcmp(wordlist[ae->idx].w,"IFUSED")==0) { - __IFUSED(ae); - } else if (curcrc==CRC_IFNUSED && strcmp(wordlist[ae->idx].w,"IFNUSED")==0) { - __IFNUSED(ae); - } else if (curcrc==CRC_IFNDEF && strcmp(wordlist[ae->idx].w,"IFNDEF")==0) { - __IFNDEF(ae); - } else if (curcrc==CRC_SWITCH && strcmp(wordlist[ae->idx].w,"SWITCH")==0) { - __SWITCH(ae); - } else if (curcrc==CRC_BREAK && strcmp(wordlist[ae->idx].w,"BREAK")==0) { - __BREAK(ae); - } else if (curcrc==CRC_DEFAULT && strcmp(wordlist[ae->idx].w,"DEFAULT")==0) { - __DEFAULT(ae); - } - while (wordlist[ae->idx].t==0) ae->idx++; - ae->idx++; - continue; - } - } - } - if (ae->imacropos) { - /* are we still in a macro? */ - if (ae->idx>=ae->macropos[0].end) { - /* are we out of all repetition blocks? */ - if (!ae->ir && !ae->iw) { - ae->imacropos=0; - - /* quand on sort du local, on récupère le dernier label global */ - if (ae->lastsuperglobal!=ae->lastgloballabel && ae->lastsuperglobal) { - if (ae->lastglobalalloc) { - MemFree(ae->lastgloballabel); - ae->lastglobalalloc=0; - } - ae->lastgloballabel=ae->lastsuperglobal; - ae->lastgloballabellen=strlen(ae->lastgloballabel); - } - } - } - } - /***************************************** - e x e c u t e i n s t r u c t i o n - *****************************************/ - executed=0; - if ((ifast=ae->fastmatch[(int)wordlist[ae->idx].w[0]])!=-1) { - while (instruction[ifast].mnemo[0]==wordlist[ae->idx].w[0]) { - if (instruction[ifast].crc==curcrc && strcmp(instruction[ifast].mnemo,wordlist[ae->idx].w)==0) { -#if TRACE_ASSEMBLE -printf("-> mnemo\n"); -#endif - instruction[ifast].makemnemo(ae); - executed=1; - break; - } - ifast++; - } - } - /***************************************** - e x e c u t e m a c r o - *****************************************/ - if (!executed) { - /* is it a macro? */ - if ((ifast=SearchMacro(ae,curcrc,wordlist[ae->idx].w))>=0) { -#if TRACE_ASSEMBLE -printf("-> macro\n"); -#endif - wordlist=__MACRO_EXECUTE(ae,ifast); - continue; - } - } - /********************************************************************* - e x e c u t e e x p r e s s i o n o r p u s h l a b e l - *********************************************************************/ - if (!ae->stop) { - if (!executed) { - /* no instruction executed, this is a label or an assignement */ - if (wordlist[ae->idx].e) { -#if TRACE_ASSEMBLE -printf("-> expr\n"); -#endif - ExpressionFastTranslate(ae,&wordlist[ae->idx].w,0); - ComputeExpression(ae,wordlist[ae->idx].w,ae->codeadr,0,0); - } else { -#if TRACE_ASSEMBLE -printf("-> label\n"); -#endif - PushLabel(ae); - } - } else { -#if TRACE_ASSEMBLE -printf("-> ajuste IDX\n"); -#endif - while (!wordlist[ae->idx].t) { - ae->idx++; - } - } - ae->idx++; - } else { -#if TRACE_ASSEMBLE -printf("-> STOP\n"); -#endif - break; - } - } -#if TRACE_ASSEMBLE - rasm_printf(ae,KVERBOSE"%d [%s] L%d [%s] fin de la liste de mots\n",ae->idx,ae->filename[wordlist[ae->idx].ifile],wordlist[ae->idx].l,wordlist[ae->idx].w); - printf("check ORG\n"); -#endif -#if TRACE_GENERALE -printf("-check ORG\n"); -#endif - - if (!ae->stop) { - /* end of assembly, check there is no opened struct */ - if (ae->getstruct) { - MakeError(ae,ae->backup_filename,ae->backup_line,"STRUCT declaration was not closed\n"); - } - /* end of assembly, close the last ORG zone */ - if (ae->io) { - ae->orgzone[ae->io-1].memend=ae->outputadr; - } - OverWriteCheck(ae); - /* end of assembly, close crunched zone (if any) */ - __internal_UpdateLZBlockIfAny(ae); - - /* end of assembly, check for opened repeat and opened while loop */ - for (i=0;iir;i++) { - MakeError(ae,ae->filename[wordlist[ae->repeat[i].start].ifile],wordlist[ae->repeat[i].start].l,"REPEAT was not closed\n"); - } - for (i=0;iiw;i++) { - MakeError(ae,ae->filename[wordlist[ae->whilewend[i].start].ifile],wordlist[ae->whilewend[i].start].l,"WHILE was not closed\n"); - } - /* is there any IF opened? -> need an evolution for a better error message */ - for (i=0;iii;i++) { - char instr[32]; - switch (ae->ifthen[i].type) { - case E_IFTHEN_TYPE_IF:strcpy(instr,"IF");break; - case E_IFTHEN_TYPE_IFNOT:strcpy(instr,"IFNOT");break; - case E_IFTHEN_TYPE_IFDEF:strcpy(instr,"IFDEF");break; - case E_IFTHEN_TYPE_IFNDEF:strcpy(instr,"IFNDEF");break; - case E_IFTHEN_TYPE_ELSE:strcpy(instr,"ELSE");break; - case E_IFTHEN_TYPE_ELSEIF:strcpy(instr,"ELSEIF");break; - case E_IFTHEN_TYPE_IFUSED:strcpy(instr,"IFUSED");break; - case E_IFTHEN_TYPE_IFNUSED:strcpy(instr,"IFNUSED");break; - default:strcpy(instr,""); - } - MakeError(ae,ae->ifthen[i].filename,ae->ifthen[i].line,"%s conditionnal block was not closed\n",instr); - } - } -#if TRACE_ASSEMBLE -printf("crunch if any\n"); -#endif - /*************************************************** - c r u n c h L Z s e c t i o n s - ***************************************************/ - if (!ae->stop || !ae->nberr) { - for (i=0;iilz;i++) { - /* compute labels and expression inside crunched blocks */ - PopAllExpression(ae,i); - - ae->curlz=i; - iorgzone=ae->lzsection[i].iorgzone; - ibank=ae->lzsection[i].ibank; - input_data=&ae->mem[ae->lzsection[i].ibank][ae->lzsection[i].memstart]; - input_size=ae->lzsection[i].memend-ae->lzsection[i].memstart; -//printf("grouik (%d) %s\n",ae->lzsection[i].lzversion,ae->lzsection[i].lzversion==8?"mizou":""); - if (!input_size) { - rasm_printf(ae,KWARNING"[%s:%d] Warning: crunched section is empty\n",GetCurrentFile(ae),ae->wl[ae->idx].l); - } else { - switch (ae->lzsection[i].lzversion) { - case 7: - #ifndef NO_3RD_PARTIES - lzdata=ZX7_compress(optimize(input_data, input_size), input_data, input_size, &slzlen); - lzlen=slzlen; - #endif - break; - case 4: - #ifndef NO_3RD_PARTIES - lzdata=LZ4_crunch(input_data,input_size,&lzlen); - #endif - break; - case 8: - #ifndef NO_3RD_PARTIES - rasm_printf(ae,KWARNING"Exomizer is crunching %.1fkb this may take a while, be patient...\n",input_size/1024.0); - - lzdata=Exomizer_crunch(input_data,input_size,&lzlen); - #endif - break; - case 48: - lzdata=LZ48_crunch(input_data,input_size,&lzlen); - break; - case 49: - lzdata=LZ49_crunch(input_data,input_size,&lzlen); - break; - default: - rasm_printf(ae,"Internal error - unknown crunch method %d\n",ae->lzsection[i].lzversion); - exit(-12); - } - } - //rasm_printf(ae,"lzsection[%d] type=%d start=%04X end=%04X crunched size=%d\n",i,ae->lzsection[i].lzversion,ae->lzsection[i].memstart,ae->lzsection[i].memend,lzlen); - - if (input_sizefilename[ae->wl[ae->lzsection[i].iw].ifile],ae->wl[ae->lzsection[i].iw].l,"As the LZ section cannot crunch data, Rasm may not guarantee assembled file!\n"); - } - - lzshift=lzlen-(ae->lzsection[i].memend-ae->lzsection[i].memstart); - if (lzshift>0) { - MemMove(ae->mem[ae->lzsection[i].ibank]+ae->lzsection[i].memend+lzshift,ae->mem[ae->lzsection[i].ibank]+ae->lzsection[i].memend,65536-ae->lzsection[i].memend-lzshift); - } else if (lzshift<0) { - lzmove=ae->orgzone[iorgzone].memend-ae->lzsection[i].memend; - if (lzmove) { - MemMove(ae->mem[ae->lzsection[i].ibank]+ae->lzsection[i].memend+lzshift,ae->mem[ae->lzsection[i].ibank]+ae->lzsection[i].memend,lzmove); - } - } - memcpy(ae->mem[ae->lzsection[i].ibank]+ae->lzsection[i].memstart,lzdata,lzlen); - MemFree(lzdata); - /******************************************************************* - l a b e l a n d e x p r e s s i o n r e l o c a t i o n - *******************************************************************/ - /* relocate labels in the same ORG zone AND after the current crunched section */ - il=ae->lzsection[i].ilabel; - while (ilil && ae->label[il].iorgzone==iorgzone && ae->label[il].ibank==ibank) { - curlabel=SearchLabel(ae,ae->label[il].iw!=-1?wordlist[ae->label[il].iw].w:ae->label[il].name,ae->label[il].crc); - /* CANNOT be NULL */ - curlabel->ptr+=lzshift; - //printf("label [%s] shifte de %d valeur #%04X -> #%04X\n",curlabel->iw!=-1?wordlist[curlabel->iw].w:curlabel->name,lzshift,curlabel->ptr-lzshift,curlabel->ptr); - il++; - } - /* relocate expressions in the same ORG zone AND after the current crunched section */ - il=ae->lzsection[i].iexpr; - while (ilie && ae->expression[il].iorgzone==iorgzone && ae->expression[il].ibank==ibank) { - ae->expression[il].wptr+=lzshift; - ae->expression[il].ptr+=lzshift; - //printf("expression [%s] shiftee ptr=#%04X wptr=#%04X\n", ae->expression[il].reference?ae->expression[il].reference:wordlist[ae->expression[il].iw].w, ae->expression[il].ptr, ae->expression[il].wptr); - il++; - } - /* relocate crunched sections in the same ORG zone AND after the current crunched section */ - il=i+1; - while (ililz && ae->lzsection[il].iorgzone==iorgzone && ae->lzsection[il].ibank==ibank) { - //rasm_printf(ae,"reloger lzsection[%d] O%d B%d\n",il,ae->lzsection[il].iorgzone,ae->lzsection[il].ibank); - ae->lzsection[il].memstart+=lzshift; - ae->lzsection[il].memend+=lzshift; - il++; - } - /* relocate current ORG zone */ - ae->orgzone[iorgzone].memend+=lzshift; - } - if (ae->ilz) { - /* compute expression placed after the last crunched block */ - PopAllExpression(ae,ae->ilz); - } - /* compute expression outside crunched blocks */ - PopAllExpression(ae,-1); - } - -/*************************************************************************************************************************************************************************************** -**************************************************************************************************************************************************************************************** - W R I T E O U T P U T F I L E S -**************************************************************************************************************************************************************************************** -***************************************************************************************************************************************************************************************/ - TMP_filename=MemMalloc(PATH_MAX); -#if 0 -for (i=0;iio;i++) { -printf("ORG[%02d] start=%04X end=%04X ibank=%d nocode=%d protect=%d\n",i,ae->orgzone[i].memstart,ae->orgzone[i].memend,ae->orgzone[i].ibank,ae->orgzone[i].nocode,ae->orgzone[i].protect); -} -#endif -#if TRACE_ASSEMBLE -printf("output files\n"); -#endif - - if (!ae->nberr && !ae->checkmode) { - - /* enregistrement des fichiers programmes par la commande SAVE */ - PopAllSave(ae); - - if (ae->nbsave==0 || ae->forcecpr || ae->forcesnapshot) { - /********************************************* - ********************************************** - C A R T R I D G E - ********************************************** - *********************************************/ - if (ae->forcecpr) { - char ChunkName[32]; - int ChunkSize; - int do_it=1; - unsigned char chunk_endian; - - if (ae->cartridge_name) { - sprintf(TMP_filename,"%s",ae->cartridge_name); - } else { - sprintf(TMP_filename,"%s.cpr",ae->outputfilename); - } - FileRemoveIfExists(TMP_filename); - - rasm_printf(ae,KIO"Write cartridge file %s\n",TMP_filename); - for (i=maxrom=0;iio;i++) { - if (ae->orgzone[i].ibank<32 && ae->orgzone[i].ibank>maxrom) maxrom=ae->orgzone[i].ibank; - } - /* construction du CPR */ - /* header blablabla */ - strcpy(ChunkName,"RIFF"); - FileWriteBinary(TMP_filename,ChunkName,4); - ChunkSize=(maxrom+1)*(16384+8)+4; - chunk_endian=ChunkSize&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); - chunk_endian=(ChunkSize>>8)&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); - chunk_endian=(ChunkSize>>16)&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); - chunk_endian=(ChunkSize>>24)&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); - sprintf(ChunkName,"AMS!"); - FileWriteBinary(TMP_filename,ChunkName,4); - -// for (j=0;jio;j++) { -//printf("ORG[%03d]=B%02d/#%04X/#%04X\n",j,ae->orgzone[j].ibank,ae->orgzone[j].memstart,ae->orgzone[j].memend); -// } - for (i=0;i<=maxrom;i++) { - offset=65536; - endoffset=0; - for (j=0;jio;j++) { - if (ae->orgzone[j].protect) continue; /* protected zones exclusion */ - /* bank data may start anywhere (typically #0000 or #C000) */ - if (ae->orgzone[j].ibank==i && ae->orgzone[j].memstart!=ae->orgzone[j].memend) { - if (ae->orgzone[j].memstartorgzone[j].memstart; - if (ae->orgzone[j].memend>endoffset) endoffset=ae->orgzone[j].memend; - } - } - if (endoffset>offset) { - int lm=0; - if (ae->iwnamebank[i]>0) { - lm=strlen(ae->wl[ae->iwnamebank[i]].w)-2; - } - rasm_printf(ae,KVERBOSE"WriteCPR bank %2d of %5d byte%s start at #%04X",i,endoffset-offset,endoffset-offset>1?"s":" ",offset); - if (endoffset-offset>16384) { - rasm_printf(ae,"\nROM is too big!!!\n"); - FileWriteBinaryClose(TMP_filename); - FileRemoveIfExists(TMP_filename); - FreeAssenv(ae); - exit(ABORT_ERROR); - } - if (lm) { - rasm_printf(ae," (%-*.*s)\n",lm,lm,ae->wl[ae->iwnamebank[i]].w+1); - } else { - rasm_printf(ae,"\n"); - } - } else { - rasm_printf(ae,KVERBOSE"WriteCPR bank %2d (empty)\n",i); - } - ChunkSize=16384; - sprintf(ChunkName,"cb%02d",i); - FileWriteBinary(TMP_filename,ChunkName,4); - chunk_endian=ChunkSize&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); - chunk_endian=(ChunkSize>>8)&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); - chunk_endian=(ChunkSize>>16)&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); - chunk_endian=(ChunkSize>>24)&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); - if (offset>0xC000) { - unsigned char filler[16384]={0}; - ChunkSize=65536-offset; - if (ChunkSize) FileWriteBinary(TMP_filename,(char*)ae->mem[i]+offset,ChunkSize); - /* ADD zeros until the end of the bank */ - FileWriteBinary(TMP_filename,(char*)filler,16384-ChunkSize); - } else { - FileWriteBinary(TMP_filename,(char*)ae->mem[i]+offset,ChunkSize); - } - } - FileWriteBinaryClose(TMP_filename); - rasm_printf(ae,"Total %d bank%s (%dK)\n",maxrom+1,maxrom+1>1?"s":"",(maxrom+1)*16); - /********************************************* - ********************************************** - S N A P S H O T - ********************************************** - *********************************************/ - } else if (ae->forcesnapshot) { - - if (ae->forcezx) { - unsigned char zxsnapheader[0x1A]={0}; - - if (ae->snapshot_name) { - sprintf(TMP_filename,"%s",ae->snapshot_name); - } else { - sprintf(TMP_filename,"%s.sna",ae->outputfilename); - } - FileRemoveIfExists(TMP_filename); - - /* do we have a bankset? */ - /* zx bootstrap */ - zxsnapheader[0x13]=0; /* 0:DI 4:EI */ - zxsnapheader[0x17]=ae->zxsnapshot.stack&0xFF; - zxsnapheader[0x18]=(ae->zxsnapshot.stack>>8)&0xFF; - zxsnapheader[0x19]=1; /* IM 1 */ - - //ae->zxsnapshot.stack&=0xFFFF; - ae->mem[0][ae->zxsnapshot.stack]=ae->zxsnapshot.run&0xFF; - ae->mem[0][ae->zxsnapshot.stack+1]=(ae->zxsnapshot.run>>8)&0xFF; - - rasm_printf(ae,KIO"Write 48K ZX snapshot file %s\n",TMP_filename); - - /* header */ - FileWriteBinary(TMP_filename,(char *)&zxsnapheader,27); - /* data */ - if (ae->bankset[0]) { - FileWriteBinary(TMP_filename,(char *)ae->mem[0]+16384,16384*3); - } else { - FileWriteBinary(TMP_filename,(char *)ae->mem[5],16384); - FileWriteBinary(TMP_filename,(char *)ae->mem[2],16384); - FileWriteBinary(TMP_filename,(char *)ae->mem[0],16384); - } - FileWriteBinaryClose(TMP_filename); - } else { - unsigned char packed[65536]={0}; - unsigned char *rlebank=NULL; - char ChunkName[16]; - int ChunkSize; - int do_it=1; - int bankset; - int noflood=0; - - if (ae->snapshot.version==2 && ae->snapshot.CPCType>2) { - if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: V2 snapshot cannot select a Plus model (forced to 6128)\n",GetCurrentFile(ae),ae->wl[ae->idx].l); - ae->snapshot.CPCType=2; /* 6128 */ - } - - if (ae->snapshot_name) { - sprintf(TMP_filename,"%s",ae->snapshot_name); - } else { - sprintf(TMP_filename,"%s.sna",ae->outputfilename); - } - FileRemoveIfExists(TMP_filename); - - maxrom=-1; - for (i=0;iio;i++) { - if (ae->orgzone[i].ibankorgzone[i].ibank>maxrom && ae->orgzone[i].memstart!=ae->orgzone[i].memend) { - maxrom=ae->orgzone[i].ibank; - } - } - - //printf("maxrom=%d\n",maxrom); - /* construction du SNA */ - if (ae->snapshot.version==2) { - if (maxrom>=4) { - ae->snapshot.dumpsize[0]=128; - } else if (maxrom>=0) { - ae->snapshot.dumpsize[0]=64; - } - } - if (maxrom==-1) { - rasm_printf(ae,KWARNING"Warning: No byte were written in snapshot memory\n"); - } else { - rasm_printf(ae,KIO"Write snapshot v%d file %s\n",ae->snapshot.version,TMP_filename); - - /* header */ - FileWriteBinary(TMP_filename,(char *)&ae->snapshot,0x100); - /* write all memory crunched */ - for (i=0;i<=maxrom;i+=4) { - bankset=i>>2; - if (ae->bankset[bankset]) { - memcpy(packed,ae->mem[i],65536); - if (i<4 || i+4>maxrom) rasm_printf(ae,KVERBOSE"WriteSNA bank %2d,%d,%d,%d packed\n",i,i+1,i+2,i+3); - else if (!noflood) {rasm_printf(ae,KVERBOSE"[...]\n");noflood=1;} - } else { - memset(packed,0,65536); - for (k=0;k<4;k++) { - offset=65536; - endoffset=0; - for (j=0;jio;j++) { - if (ae->orgzone[j].protect) continue; /* protected zones exclusion */ - /* bank data may start anywhere (typically #0000 or #C000) */ - if (ae->orgzone[j].ibank==i+k && ae->orgzone[j].memstart!=ae->orgzone[j].memend) { - if (ae->orgzone[j].memstartorgzone[j].memstart; - if (ae->orgzone[j].memend>endoffset) endoffset=ae->orgzone[j].memend; - } - } - if (endoffset-offset>16384) { - rasm_printf(ae,KERROR"\nBANK is too big!!!\n"); - FileWriteBinaryClose(TMP_filename); - FileRemoveIfExists(TMP_filename); - FreeAssenv(ae); - exit(ABORT_ERROR); - } - /* banks are gathered in the 64K block */ - if (offset>0xC000) { - ChunkSize=65536-offset; - memcpy(packed+k*16384,(char*)ae->mem[i+k]+offset,ChunkSize); - } else { - memcpy(packed+k*16384,(char*)ae->mem[i+k]+offset,16384); - } - - if (endoffset>offset) { - int lm=0; - if (ae->iwnamebank[i]>0) { - lm=strlen(ae->wl[ae->iwnamebank[i]].w)-2; - } - if (i<4 || i+4>maxrom) rasm_printf(ae,KVERBOSE"WriteSNA bank %2d of %5d byte%s start at #%04X",i+k,endoffset-offset,endoffset-offset>1?"s":" ",offset); - else if (!noflood) {rasm_printf(ae,KVERBOSE"[...]\n");noflood=1;} - if (endoffset-offset>16384) { - rasm_printf(ae,KERROR"\nRAM block is too big!!!\n"); - FileWriteBinaryClose(TMP_filename); - FileRemoveIfExists(TMP_filename); - FreeAssenv(ae); - exit(ABORT_ERROR); - } - if (lm) { - if (i<4 || i+4>maxrom) rasm_printf(ae,KVERBOSE" (%-*.*s)\n",lm,lm,ae->wl[ae->iwnamebank[i+k]].w+1); - } else { - if (i<4 || i+4>maxrom) rasm_printf(ae,"\n"); - } - } else { - if (i<4 || i+4>maxrom) rasm_printf(ae,KVERBOSE"WriteSNA bank %2d (empty)\n",i+k); - else if (!noflood) {rasm_printf(ae,KVERBOSE"[...]\n");noflood=1;} - } - } - } - - if (ae->snapshot.version==2) { - /* snapshot v2 */ - FileWriteBinary(TMP_filename,(char*)&packed,65536); - if (bankset) { - /* v2 snapshot is 128K maximum */ - maxrom=7; - break; - } - } else { - /* compression par défaut avec snapshot v3 */ - rlebank=EncodeSnapshotRLE(packed,&ChunkSize); - - if (bankset>=0 && bankset<=8) { - sprintf(ChunkName,"MEM%d",bankset); - } else if (bankset>8 && bankset<=0x40) { - /* extended chunk for 4M extension -> MX09 to MX40 (hexa numbered) */ - sprintf(ChunkName,"MX%02X",bankset); - } else { - MakeError(ae,"(core)",0,"internal error during snapshot write, please report (%d)\n",bankset); - } - - FileWriteBinary(TMP_filename,ChunkName,4); - if (rlebank!=NULL) { - FileWriteBinary(TMP_filename,(char*)&ChunkSize,4); - FileWriteBinary(TMP_filename,(char*)rlebank,ChunkSize); - MemFree(rlebank); - } else { - ChunkSize=65536; - FileWriteBinary(TMP_filename,(char*)&packed,ChunkSize); - } - } - } - - /************************************************************** - snapshot additional chunks in v3+ only - **************************************************************/ - if (ae->snapshot.version>=3) { - /* export breakpoint */ - if (ae->export_snabrk) { - /* BRKS chunk for Winape emulator (unofficial) - - 2 bytes - adress - 1 byte - 0=base 64K / 1=extended - 2 bytes - condition (zeroed) - */ - struct s_breakpoint breakpoint={0}; - unsigned char *brkschunk=NULL; - unsigned int idx=8; - - /* add labels and local labels to breakpoint pool (if any) */ - for (i=0;iil;i++) { - if (!ae->label[i].name) { - if (strncmp(ae->wl[ae->label[i].iw].w,"BRK",3)==0) { - breakpoint.address=ae->label[i].ptr; - if (ae->label[i].ibank>3) breakpoint.bank=1; else breakpoint.bank=0; - ObjectArrayAddDynamicValueConcat((void **)&ae->breakpoint,&ae->ibreakpoint,&ae->maxbreakpoint,&breakpoint,sizeof(struct s_breakpoint)); - } - } else { - if (strncmp(ae->label[i].name,"@BRK",4)==0 || strstr(ae->label[i].name,".BRK")) { - breakpoint.address=ae->label[i].ptr; - if (ae->label[i].ibank>3) breakpoint.bank=1; else breakpoint.bank=0; - ObjectArrayAddDynamicValueConcat((void **)&ae->breakpoint,&ae->ibreakpoint,&ae->maxbreakpoint,&breakpoint,sizeof(struct s_breakpoint)); - } - } - } - - brkschunk=MemMalloc(ae->ibreakpoint*5+8); - strcpy((char *)brkschunk,"BRKS"); - - for (i=0;iibreakpoint;i++) { - brkschunk[idx++]=ae->breakpoint[i].address&0xFF; - brkschunk[idx++]=(ae->breakpoint[i].address&0xFF00)/256; - brkschunk[idx++]=ae->breakpoint[i].bank; - brkschunk[idx++]=0; - brkschunk[idx++]=0; - } - - idx-=8; - brkschunk[4]=idx&0xFF; - brkschunk[5]=(idx>>8)&0xFF; - brkschunk[6]=(idx>>16)&0xFF; - brkschunk[7]=(idx>>24)&0xFF; - FileWriteBinary(TMP_filename,(char*)brkschunk,idx+8); // 8 bytes for the chunk header - MemFree(brkschunk); - - - /* BRKC chunk for ACE emulator - minimal integration - */ - brkschunk=MemMalloc(ae->ibreakpoint*256); - strcpy((char *)brkschunk,"BRKC"); - idx=8; - - for (i=0;iibreakpoint;i++) { - brkschunk[idx++]=0; /* 0:Execution */ - brkschunk[idx++]=0; - brkschunk[idx++]=0; - brkschunk[idx++]=0; - brkschunk[idx++]=ae->breakpoint[i].address&0xFF; - brkschunk[idx++]=(ae->breakpoint[i].address&0xFF00)/256; - for (j=0;j<2+1+1+2+4+128;j++) { - brkschunk[idx++]=0; - } - sprintf((char *)brkschunk+idx,"breakpoint%d",i); /* breakpoint user name? */ - idx+=64+8; - } - idx-=8; - brkschunk[4]=idx&0xFF; - brkschunk[5]=(idx>>8)&0xFF; - brkschunk[6]=(idx>>16)&0xFF; - brkschunk[7]=(idx>>24)&0xFF; - FileWriteBinary(TMP_filename,(char *)brkschunk,idx+8); // 8 bytes for the chunk header - MemFree(brkschunk); - } - /* export optionnel des symboles */ - if (ae->export_sna) { - /* SYMB chunk for ACE emulator - - 1 byte - name size - n bytes - name (without 0 to end the string) - 6 bytes - reserved for future use - 2 bytes - shitty big endian adress for the symbol - */ - - unsigned char *symbchunk=NULL; - unsigned int idx=8; - int symbol_len; - - symbchunk=MemMalloc(8+ae->il*(1+255+6+2)); - strcpy((char *)symbchunk,"SYMB"); - - for (i=0;iil;i++) { - if (!ae->label[i].name) { - symbol_len=strlen(ae->wl[ae->label[i].iw].w); - if (symbol_len>255) symbol_len=255; - symbchunk[idx++]=symbol_len; - memcpy(symbchunk+idx,ae->wl[ae->label[i].iw].w,symbol_len); - idx+=symbol_len; - memset(symbchunk+idx,0,6); - idx+=6; - symbchunk[idx++]=(ae->label[i].ptr&0xFF00)/256; - symbchunk[idx++]=ae->label[i].ptr&0xFF; - } else { - if (ae->export_local || !ae->label[i].local) { - symbol_len=strlen(ae->label[i].name); - if (symbol_len>255) symbol_len=255; - symbchunk[idx++]=symbol_len; - memcpy(symbchunk+idx,ae->label[i].name,symbol_len); - idx+=symbol_len; - memset(symbchunk+idx,0,6); - idx+=6; - symbchunk[idx++]=(ae->label[i].ptr&0xFF00)/256; - symbchunk[idx++]=ae->label[i].ptr&0xFF; - } - } - } - if (ae->export_var) { - unsigned char *subchunk=NULL; - int retidx=0; - /* var are part of fast tree search structure */ - subchunk=SnapshotDicoTree(ae,&retidx); - if (retidx) { - symbchunk=MemRealloc(symbchunk,idx+retidx); - memcpy(symbchunk+idx,subchunk,retidx); - idx+=retidx; - SnapshotDicoInsert("FREE",0,&retidx); - } - } - if (ae->export_equ) { - symbchunk=MemRealloc(symbchunk,idx+ae->ialias*(1+255+6+2)); - - for (i=0;iialias;i++) { - int tmpptr; - symbol_len=strlen(ae->alias[i].alias); - if (symbol_len>255) symbol_len=255; - symbchunk[idx++]=symbol_len; - memcpy(symbchunk+idx,ae->alias[i].alias,symbol_len); - idx+=symbol_len; - memset(symbchunk+idx,0,6); - idx+=6; - tmpptr=RoundComputeExpression(ae,ae->alias[i].translation,0,0,0); - symbchunk[idx++]=(tmpptr&0xFF00)/256; - symbchunk[idx++]=tmpptr&0xFF; - } - } - idx-=8; - symbchunk[4]=idx&0xFF; - symbchunk[5]=(idx>>8)&0xFF; - symbchunk[6]=(idx>>16)&0xFF; - symbchunk[7]=(idx>>24)&0xFF; - FileWriteBinary(TMP_filename,(char*)symbchunk,idx+8); // 8 bytes for the chunk header - } - } else { - if (ae->export_snabrk) { - if (!ae->nowarning) rasm_printf(ae,KWARNING"Warning: breakpoint export is not supported with snapshot version 2\n"); - } - if (ae->export_sna) { - if (!ae->nowarning) rasm_printf(ae,KWARNING"Warning: symbol export is not supported with snapshot version 2\n"); - } - } - - FileWriteBinaryClose(TMP_filename); - maxrom=(maxrom>>2)*4+4; - rasm_printf(ae,KAYGREEN"Total %d bank%s (%dK)\n",maxrom,maxrom>1?"s":"",(maxrom)*16); - } - } - /********************************************* - ********************************************** - B I N A R Y F I L E - ********************************************** - *********************************************/ - } else { - int lastspaceid=-1; - - if (ae->binary_name) { - sprintf(TMP_filename,"%s",ae->binary_name); - } else { - sprintf(TMP_filename,"%s.bin",ae->outputfilename); - } - FileRemoveIfExists(TMP_filename); - - /* en mode binaire classique on va recherche le dernier espace mémoire dans lequel on a travaillé qui n'est pas en 'nocode' */ - for (i=0;iio;i++) { - /* uniquement si le ORG a ete suivi d'ecriture */ - if (ae->orgzone[i].memstart!=ae->orgzone[i].memend && ae->orgzone[i].nocode!=1) { - lastspaceid=ae->orgzone[i].ibank; - } - } - if (lastspaceid!=-1) { - for (i=0;iio;i++) { - if (ae->orgzone[i].protect) continue; /* protected zones exclusion */ - /* uniquement si le ORG a ete suivi d'ecriture et n'est pas en 'nocode' */ - if (ae->orgzone[i].ibank==lastspaceid && ae->orgzone[i].memstart!=ae->orgzone[i].memend && ae->orgzone[i].nocode!=1) { - if (ae->orgzone[i].memstartorgzone[i].memstart; - if (ae->orgzone[i].memend>maxmem) maxmem=ae->orgzone[i].memend; - } - } - } - if (maxmem-minmem<=0) { - if (!ae->stop) { - if (!ae->nowarning) rasm_printf(ae,KWARNING"Warning: Not a single byte to output\n"); - } - if (ae->flux) { - *lenout=0; - } - } else { - if (!ae->flux) { - rasm_printf(ae,KIO"Write binary file %s (%d byte%s)\n",TMP_filename,maxmem-minmem,maxmem-minmem>1?"s":""); - if (ae->amsdos) { - AmsdosHeader=MakeAMSDOSHeader(minmem,minmem,maxmem,TMP_filename); //@@TODO - FileWriteBinary(TMP_filename,(char *)AmsdosHeader,128); - } - if (maxmem-minmem>0) { - FileWriteBinary(TMP_filename,(char*)ae->mem[lastspaceid]+minmem,maxmem-minmem); - FileWriteBinaryClose(TMP_filename); - } else { - if (ae->amsdos) { - FileWriteBinaryClose(TMP_filename); - } - } - } else { - *dataout=MemMalloc(maxmem-minmem+1); - memcpy(*dataout,ae->mem[lastspaceid]+minmem,maxmem-minmem); - *lenout=maxmem-minmem; - } - } - } - } - /******************************** - ********************************* - U N U S E D W A R N I N G - ********************************* - ********************************/ - if (ae->warn_unused) { - for (i=0;iialias;i++) { - if (strcmp(ae->alias[i].alias,"IX") && strcmp(ae->alias[i].alias,"IY")) { - if (!ae->alias[i].used) { - rasm_printf(ae,KWARNING"[%s:%d] Warning: alias %s declared but not used\n",ae->filename[ae->wl[ae->alias[i].iw].ifile],ae->wl[ae->alias[i].iw].l,ae->alias[i].alias); - } - } - } - WarnLabelTree(ae); - WarnDicoTree(ae); - } - - /**************************** - ***************************** - S Y M B O L E X P O R T - ***************************** - ****************************/ - if (ae->export_sym && !ae->export_sna) { - char *SymbolFileName; - SymbolFileName=MemMalloc(PATH_MAX); - -#define MAKE_SYMBOL_NAME if (ae->symbol_name) {sprintf(TMP_filename,"%s",ae->symbol_name);} else {sprintf(TMP_filename,"%s.sym",ae->outputfilename);} - - MAKE_SYMBOL_NAME - FileRemoveIfExists(TMP_filename); - - if (ae->export_multisym) { - /* multi-remove before writes */ - for (i=0;inbbank;i++) { - if (ae->symbol_name) { - sprintf(TMP_filename,"%s.bank%d",ae->symbol_name,i); - } else { - sprintf(TMP_filename,"%s.sym.bank%d",ae->outputfilename,i); - } - FileRemoveIfExists(TMP_filename); - } - rasm_printf(ae,KIO"Write symbol files %s.bank*\n",TMP_filename); - } else { - rasm_printf(ae,KIO"Write symbol file %s\n",TMP_filename); - } - - switch (ae->export_sym) { - case 5: - /* ZX export */ - for (i=0;iil;i++) { - if (ae->label[i].autorise_export) { - if (ae->export_multisym) { - if (ae->symbol_name) { - sprintf(TMP_filename,"%s.bank%d",ae->symbol_name,ae->label[i].ibank); - } else { - sprintf(TMP_filename,"%s.sym.bank%d",ae->outputfilename,ae->label[i].ibank); - } - } - - if (!ae->label[i].name) { - sprintf(symbol_line,"%d:%04X %s\n",ae->label[i].ibank,ae->label[i].ptr,ae->wl[ae->label[i].iw].w); - FileWriteLine(TMP_filename,symbol_line); - } else { - if (ae->export_local || !ae->label[i].local) { - sprintf(symbol_line,"%d:%04X %s\n",ae->label[i].ibank,ae->label[i].ptr,ae->label[i].name); - FileWriteLine(TMP_filename,symbol_line); - } - } - } - } - FileWriteLineClose(TMP_filename); - MAKE_SYMBOL_NAME - if (ae->export_var) { - /* var are part of fast tree search structure */ - ExportDicoTree(ae,TMP_filename,"%s %04X"); - } - if (ae->export_equ) { - for (i=0;iialias;i++) { - if (strcmp(ae->alias[i].alias,"IX") && strcmp(ae->alias[i].alias,"IY")) { - sprintf(symbol_line,"%04X %s\n",RoundComputeExpression(ae,ae->alias[i].translation,0,-ae->alias[i].iw,0),ae->alias[i].alias); - FileWriteLine(TMP_filename,symbol_line); - } - } - } - break; - case 4: - /* flexible */ - for (i=0;iil;i++) { - if (ae->label[i].autorise_export) { - if (ae->export_multisym) { - if (ae->symbol_name) { - sprintf(TMP_filename,"%s.bank%d",ae->symbol_name,ae->label[i].ibank); - } else { - sprintf(TMP_filename,"%s.sym.bank%d",ae->outputfilename,ae->label[i].ibank); - } - } - - if (!ae->label[i].name) { - sprintf(symbol_line,ae->flexible_export,ae->wl[ae->label[i].iw].w,ae->label[i].ptr); - FileWriteLine(TMP_filename,symbol_line); - } else { - if (ae->export_local || !ae->label[i].local) { - sprintf(symbol_line,ae->flexible_export,ae->label[i].name,ae->label[i].ptr); - FileWriteLine(TMP_filename,symbol_line); - } - } - } - } - MAKE_SYMBOL_NAME - if (ae->export_var) { - /* var are part of fast tree search structure */ - ExportDicoTree(ae,TMP_filename,ae->flexible_export); - } - if (ae->export_equ) { - for (i=0;iialias;i++) { - if (strcmp(ae->alias[i].alias,"IX") && strcmp(ae->alias[i].alias,"IY")) { - sprintf(symbol_line,ae->flexible_export,ae->alias[i].alias,RoundComputeExpression(ae,ae->alias[i].translation,0,-ae->alias[i].iw,0)); - FileWriteLine(TMP_filename,symbol_line); - } - } - } - FileWriteLineClose(TMP_filename); - break; - case 3: - /* winape */ - for (i=0;iil;i++) { - if (ae->label[i].autorise_export) { - if (ae->export_multisym) { - if (ae->symbol_name) { - sprintf(TMP_filename,"%s.bank%d",ae->symbol_name,ae->label[i].ibank); - } else { - sprintf(TMP_filename,"%s.sym.bank%d",ae->outputfilename,ae->label[i].ibank); - } - } - if (!ae->label[i].name) { - sprintf(symbol_line,"%s #%04X\n",ae->wl[ae->label[i].iw].w,ae->label[i].ptr); - FileWriteLine(TMP_filename,symbol_line); - } else { - if (ae->export_local || !ae->label[i].local) { - sprintf(symbol_line,"%s #%04X\n",ae->label[i].name,ae->label[i].ptr); - FileWriteLine(TMP_filename,symbol_line); - } - } - } - } - MAKE_SYMBOL_NAME - if (ae->export_var) { - /* var are part of fast tree search structure */ - ExportDicoTree(ae,TMP_filename,"%s #%04X\n"); - } - if (ae->export_equ) { - for (i=0;iialias;i++) { - if (strcmp(ae->alias[i].alias,"IX") && strcmp(ae->alias[i].alias,"IY")) { - sprintf(symbol_line,"%s #%04X\n",ae->alias[i].alias,RoundComputeExpression(ae,ae->alias[i].translation,0,-ae->alias[i].iw,0)); - FileWriteLine(TMP_filename,symbol_line); - } - } - } - FileWriteLineClose(TMP_filename); - break; - case 2: - /* pasmo */ - for (i=0;iil;i++) { - if (ae->label[i].autorise_export) { - if (ae->export_multisym) { - if (ae->symbol_name) { - sprintf(TMP_filename,"%s.bank%d",ae->symbol_name,ae->label[i].ibank); - } else { - sprintf(TMP_filename,"%s.sym.bank%d",ae->outputfilename,ae->label[i].ibank); - } - } - if (!ae->label[i].name) { - sprintf(symbol_line,"%s EQU 0%04XH\n",ae->wl[ae->label[i].iw].w,ae->label[i].ptr); - FileWriteLine(TMP_filename,symbol_line); - } else { - if (ae->export_local || !ae->label[i].local) { - sprintf(symbol_line,"%s EQU 0%04XH\n",ae->label[i].name,ae->label[i].ptr); - FileWriteLine(TMP_filename,symbol_line); - } - } - } - } - MAKE_SYMBOL_NAME - if (ae->export_var) { - /* var are part of fast tree search structure */ - ExportDicoTree(ae,TMP_filename,"%s EQU 0%04XH\n"); - } - if (ae->export_equ) { - for (i=0;iialias;i++) { - if (strcmp(ae->alias[i].alias,"IX") && strcmp(ae->alias[i].alias,"IY")) { - sprintf(symbol_line,"%s EQU 0%04XH\n",ae->alias[i].alias,RoundComputeExpression(ae,ae->alias[i].translation,0,-ae->alias[i].iw,0)); - FileWriteLine(TMP_filename,symbol_line); - } - } - } - FileWriteLineClose(TMP_filename); - break; - case 1: - /* Rasm */ - for (i=0;iil;i++) { - if (ae->label[i].autorise_export) { - if (ae->export_multisym) { - if (ae->symbol_name) { - sprintf(TMP_filename,"%s.bank%d",ae->symbol_name,ae->label[i].ibank); - } else { - sprintf(TMP_filename,"%s.sym.bank%d",ae->outputfilename,ae->label[i].ibank); - } - } - if (!ae->label[i].name) { - sprintf(symbol_line,"%s #%X B%d\n",ae->wl[ae->label[i].iw].w,ae->label[i].ptr,ae->label[i].ibank>31?0:ae->label[i].ibank); - FileWriteLine(TMP_filename,symbol_line); - } else { - if (ae->export_local) { - sprintf(symbol_line,"%s #%X B%d\n",ae->label[i].name,ae->label[i].ptr,ae->label[i].ibank>31?0:ae->label[i].ibank); - FileWriteLine(TMP_filename,symbol_line); - } - } - } - } - MAKE_SYMBOL_NAME - if (ae->export_var) { - /* var are part of fast tree search structure */ - ExportDicoTree(ae,TMP_filename,"%s #%X B0\n"); - } - if (ae->export_equ) { - for (i=0;iialias;i++) { - if (strcmp(ae->alias[i].alias,"IX") && strcmp(ae->alias[i].alias,"IY") && ae->alias[i].autorise_export) { - sprintf(symbol_line,"%s #%X B0\n",ae->alias[i].alias,RoundComputeExpression(ae,ae->alias[i].translation,0,-ae->alias[i].iw,0)); - FileWriteLine(TMP_filename,symbol_line); - } - } - } - FileWriteLineClose(TMP_filename); - break; - case 0: - default:break; - } - MemFree(SymbolFileName); - } - /********************************* - ********************************** - B R E A K P O I N T S - ********************************** - *********************************/ - if (ae->export_brk) { - struct s_breakpoint breakpoint={0}; - - if (ae->breakpoint_name) { - sprintf(TMP_filename,"%s",ae->breakpoint_name); - } else { - sprintf(TMP_filename,"%s.brk",ae->outputfilename); - } - FileRemoveIfExists(TMP_filename); - - /* add labels and local labels to breakpoint pool (if any) */ - for (i=0;iil;i++) { - if (!ae->label[i].name) { - if (strncmp(ae->wl[ae->label[i].iw].w,"BRK",3)==0) { - breakpoint.address=ae->label[i].ptr; - if (ae->label[i].ibank>3) breakpoint.bank=1; else breakpoint.bank=0; - ObjectArrayAddDynamicValueConcat((void **)&ae->breakpoint,&ae->ibreakpoint,&ae->maxbreakpoint,&breakpoint,sizeof(struct s_breakpoint)); - } - } else { - if (strncmp(ae->label[i].name,"@BRK",4)==0) { - breakpoint.address=ae->label[i].ptr; - if (ae->label[i].ibank>3) breakpoint.bank=1; else breakpoint.bank=0; - ObjectArrayAddDynamicValueConcat((void **)&ae->breakpoint,&ae->ibreakpoint,&ae->maxbreakpoint,&breakpoint,sizeof(struct s_breakpoint)); - } - } - } - - if (ae->ibreakpoint) { - rasm_printf(ae,KIO"Write breakpoint file %s\n",TMP_filename); - for (i=0;iibreakpoint;i++) { - sprintf(symbol_line,"#%04X\n",ae->breakpoint[i].address); - FileWriteLine(TMP_filename,symbol_line); - } - FileWriteLineClose(TMP_filename); - } else { - if (!ae->nowarning) rasm_printf(ae,KWARNING"Warning: no breakpoint to output (previous file [%s] deleted anyway)\n",TMP_filename); - } - } - - } else { - if (!ae->dependencies) rasm_printf(ae,KERROR"%d error%s\n",ae->nberr,ae->nberr>1?"s":""); - } -#if TRACE_ASSEMBLE -printf("dependencies\n"); -#endif -/******************************************************************************************* - E X P O R T D E P E N D E N C I E S -*******************************************************************************************/ - if (ae->dependencies) { - int trigdep=0; - - /* depends ALL */ - if (ae->outputfilename && strcmp(ae->outputfilename,"rasmoutput")) { - trigdep=1; - printf("%s",ae->outputfilename); - if (ae->dependencies==E_DEPENDENCIES_MAKE) printf(" "); else printf("\n"); - } - for (i=1;iifile;i++) { - trigdep=1; - SimplifyPath(ae->filename[i]); - printf("%s",ae->filename[i]); - if (ae->dependencies==E_DEPENDENCIES_MAKE) printf(" "); else printf("\n"); - } - for (i=0;iih;i++) { - trigdep=1; - SimplifyPath(ae->hexbin[i].filename); - printf("%s",ae->hexbin[i].filename); - if (ae->dependencies==E_DEPENDENCIES_MAKE) printf(" "); else printf("\n"); - } - if (ae->dependencies==E_DEPENDENCIES_MAKE && trigdep) printf("\n"); - } - -/******************************************************************************************* - V E R B O S E S H I T -*******************************************************************************************/ -#if TRACE_ASSEMBLE - rasm_printf(ae,KVERBOSE"------ statistics ------------------\n"); - rasm_printf(ae,KVERBOSE"%d file%s\n",ae->ifile,ae->ifile>1?"s":""); - rasm_printf(ae,KVERBOSE"%d binary include%s\n",ae->ih,ae->ih>1?"s":""); - rasm_printf(ae,KVERBOSE"%d word%s\n",ae->nbword-1,ae->nbword>2?"s":""); - rasm_printf(ae,KVERBOSE"%d label%s\n",ae->il,ae->il>1?"s":""); - rasm_printf(ae,KVERBOSE"%d struct%s\n",ae->irasmstruct,ae->irasmstruct>1?"s":""); - rasm_printf(ae,KVERBOSE"%d var%s\n",ae->idic,ae->idic>1?"s":""); - rasm_printf(ae,KVERBOSE"%d expression%s\n",ae->ie,ae->ie>1?"s":""); - rasm_printf(ae,KVERBOSE"%d macro%s\n",ae->imacro,ae->imacro>1?"s":""); - rasm_printf(ae,KVERBOSE"%d alias%s\n",ae->ialias,ae->ialias>1?"s":""); - rasm_printf(ae,KVERBOSE"%d ORG zone%s\n",ae->io-1,ae->io>2?"s":""); - rasm_printf(ae,KVERBOSE"%d virtual space%s\n",ae->nbbank,ae->nbbank>1?"s":""); -#endif - -/******************************************************************************************* - C L E A N U P -*******************************************************************************************/ -#if TRACE_ASSEMBLE -printf("cleanup\n"); -#endif -#if TRACE_GENERALE -printf("-cleanup\n"); -#endif - if (TMP_filename) MemFree(TMP_filename); - if (ae->nberr) { - ok=-1; - if (ae->flux && *dataout) { - MemFree(*dataout); - *dataout=NULL; - } - if (lenout) *lenout=0; - } else { - ok=0; - } - - FreeAssenv(ae); -#if TRACE_ASSEMBLE -printf("end of assembling\n"); -#endif -#if TRACE_GENERALE -printf("-end ok=%d\n",ok); -#endif - return ok; -} - - -void EarlyPrepSrc(struct s_assenv *ae, char **listing, char *filename) { - int l,idx,c,quote_type=0; - int mlc_start,mlc_idx; - - /* virer les commentaires en ;, // mais aussi multi-lignes et convertir les decalages, passer les chars en upper case */ - l=idx=0; - while (listing[l]) { - c=listing[l][idx++]; - - if (!c) { - l++; - idx=0; - continue; - } else if (!quote_type) { - /* upper case */ - if (c>='a' && c<='z') { - listing[l][idx-1]=c=c-'a'+'A'; - } - - if (c=='\'' && idx>2 && strncmp(&listing[l][idx-3],"AF'",3)==0) { - /* il ne faut rien faire */ - } else if (c=='"' || c=='\'') { - quote_type=c; - } else if (c==';' || (c=='/' && listing[l][idx]=='/')) { - idx--; - while (listing[l][idx] && listing[l][idx]!=0x0D && listing[l][idx]!=0x0A) listing[l][idx++]=':'; - idx--; - } else if (c=='>' && listing[l][idx]=='>' && !quote_type) { - listing[l][idx-1]=']'; - listing[l][idx++]=' '; - continue; - } else if (c=='<' && listing[l][idx]=='<' && !quote_type) { - listing[l][idx-1]='['; - listing[l][idx++]=' '; - continue; - } else if (c=='/' && listing[l][idx]=='*' && !quote_type) { - /* multi-line comment */ - mlc_start=l; - mlc_idx=idx-1; - idx++; - while (1) { - c=listing[l][idx++]; - if (!c) { - idx=0; - l++; - if (!listing[l]) { - MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"opened comment to the end of the file\n",filename,l+1); - return; - } - } else if (c=='*' && listing[l][idx]=='/') { - idx++; - break; - } - } - /* merge */ - if (mlc_start==l) { - /* on the same line */ - while (mlc_idx=*ml) { - *il=*ml=*il+nbinsert; - *reflisting=MemRealloc(*reflisting,sizeof(struct s_listing)*(*ml)); - } else { - *il=*il+nbinsert; - } - listing=*reflisting; - MemMove(&listing[idx+1+nbinsert],&listing[idx+1],(bil-idx-1)*sizeof(struct s_listing)); - - for (li=0;zelines[li];li++) { - listing[idx+1+li].ifile=ifile; - listing[idx+1+li].iline=li+1; - listing[idx+1+li].listing=zelines[li]; - } -} - -int cmpkeyword(const void * a, const void * b) -{ - struct s_asm_keyword *sa,*sb; - sa=(struct s_asm_keyword *)a; - sb=(struct s_asm_keyword *)b; - return strcmp(sa->mnemo,sb->mnemo); -} - -struct s_assenv *PreProcessing(char *filename, int flux, const char *datain, int datalen, struct s_parameter *param) -{ - #undef FUNC - #define FUNC "PreProcessing" - - #define CharWord "@ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.=_($)][+-*/^%#|&'\"\\m}{[]" - - struct s_assenv *ae=NULL; - struct s_wordlist curw={0}; - struct s_wordlist *wordlist=NULL; - int nbword=0,maxword=0; - char **zelines=NULL; - - char *filename_toread; - - struct s_macro_fast *MacroFast=NULL; - int idxmacrofast=0,maxmacrofast=0; - - struct s_listing *listing=NULL; - struct s_listing curlisting; - int ilisting=0,maxlisting=0; - - char **listing_include=NULL; - int i,j,l=0,idx=0,c=0,li,le; - char Automate[256]={0}; - struct s_hexbin curhexbin; - char *newlistingline=NULL; - unsigned char *newdata; - struct s_label curlabel={0}; - char *labelsep1; - char **labelines=NULL; - /* state machine buffer */ - unsigned char *mem=NULL; - char *w=NULL,*wtmp=NULL; - int lw=0,mw=256; - char *bval=NULL; - int ival=0,sval=256; - char *qval=NULL; - int iqval=0,sqval=256; - struct s_repeat_index *TABrindex=NULL; - struct s_repeat_index *TABwindex=NULL; - struct s_repeat_index rindex={0}; - struct s_repeat_index windex={0}; - int nri=0,mri=0,ri=0; - int nwi=0,mwi=0,wi=0; - /* state machine trigger */ - int waiting_quote=0,lquote; - int macro_trigger=0; - int escape_code=0; - int quote_type=0; - int incbin=0,include=0,crunch=0; - int rewrite=0,hadcomma=0; - int nbinstruction; - int ifast,texpr; - int ispace=0; - -#if TRACE_GENERALE -printf("*** preprocessing ***\n"); -#endif - -#if TRACE_PREPRO -printf("start prepro, alloc assenv\n"); -#endif - - windex.cl=-1; - windex.cidx=-1; - rindex.cl=-1; - rindex.cidx=-1; - -#if TRACE_PREPRO -printf("malloc\n"); -#endif - ae=MemMalloc(sizeof(struct s_assenv)); -#if TRACE_PREPRO -printf("memset\n"); -#endif - memset(ae,0,sizeof(struct s_assenv)); - -#if TRACE_PREPRO -printf("paramz 1\n"); -#endif - if (param) { - ae->export_local=param->export_local; - ae->export_sym=param->export_sym; - ae->export_var=param->export_var; - ae->export_equ=param->export_equ; - ae->export_sna=param->export_sna; - ae->export_snabrk=param->export_snabrk; - if (param->export_sna || param->export_snabrk) { - ae->forcesnapshot=1; - } - ae->export_brk=param->export_brk; - ae->warn_unused=param->warn_unused; - ae->edskoverwrite=param->edskoverwrite; - ae->rough=param->rough; - ae->as80=param->as80; - ae->dams=param->dams; - ae->macrovoid=param->macrovoid; - if (param->v2) { - ae->forcesnapshot=1; - ae->snapshot.version=2; - } else { - ae->snapshot.version=3; - } - ae->maxerr=param->maxerr; - ae->extended_error=param->extended_error; - ae->nowarning=param->nowarning; - ae->breakpoint_name=param->breakpoint_name; - ae->symbol_name=param->symbol_name; - ae->binary_name=param->binary_name; - ae->flexible_export=param->flexible_export; - ae->cartridge_name=param->cartridge_name; - ae->snapshot_name=param->snapshot_name; - ae->checkmode=param->checkmode; - if (param->rough) ae->maxam=0; else ae->maxam=1; - /* additional symbols */ - for (i=0;insymb;i++) { - char *sep; - sep=strchr(param->symboldef[i],'='); - if (sep) { - *sep=0; - ExpressionSetDicoVar(ae,param->symboldef[i],atof(sep+1)); - } - } - if (param->msymb) { - MemFree(param->symboldef); - param->nsymb=param->msymb=0; - } - /* include paths */ - ae->includepath=param->pathdef; - ae->ipath=param->npath; - ae->mpath=param->mpath; - /* old inline params */ - ae->dependencies=param->dependencies; - } -#if TRACE_PREPRO -printf("init 0\n"); -#endif -#if TRACE_GENERALE -printf("-init\n"); -#endif - /* generic init */ - ae->ctx1.maxivar=1; - ae->ctx2.maxivar=1; - ae->computectx=&ae->ctx1; - ae->flux=flux; - /* check snapshot structure */ - if (sizeof(ae->snapshot)!=0x100 || &ae->snapshot.fdd.motorstate-(unsigned char*)&ae->snapshot!=0x9C || &ae->snapshot.crtcstate.model-(unsigned char*)&ae->snapshot!=0xA4 - || &ae->snapshot.romselect-(unsigned char*)&ae->snapshot!=0x55 - || &ae->snapshot.interruptrequestflag-(unsigned char*)&ae->snapshot!=0xB4 - || &ae->snapshot.CPCType-(unsigned char*)&ae->snapshot!=0x6D) { - rasm_printf(ae,"snapshot structure integrity check KO\n"); - exit(349); - } - - for (i=0;i<4;i++) { - ae->bankgate[i]=0x7FC0; /* video memory has no paging */ - ae->setgate[i]=0x7FC0; /* video memory has no paging */ - } - for (i=0;i<256;i++) { - /* 4M expansion support on lower gate array port */ - ae->bankgate[i+4]=0x7FC4+(i&3)+((i&31)>>2)*8-0x100*(i>>5); - ae->setgate[i+4] =0x7FC2 +((i&31)>>2)*8-0x100*(i>>5); - //printf("%04X %04X\n",ae->bankgate[i+4],ae->setgate[i+4]); - } - - memcpy(ae->snapshot.idmark,"MV - SNA",8); - ae->snapshot.registers.IM=1; - - ae->snapshot.gatearray.palette[0]=0x04; - ae->snapshot.gatearray.palette[1]=0x0A; - ae->snapshot.gatearray.palette[2]=0x15; - ae->snapshot.gatearray.palette[3]=0x1C; - ae->snapshot.gatearray.palette[4]=0x18; - ae->snapshot.gatearray.palette[5]=0x1D; - ae->snapshot.gatearray.palette[6]=0x0C; - ae->snapshot.gatearray.palette[7]=0x05; - ae->snapshot.gatearray.palette[8]=0x0D; - ae->snapshot.gatearray.palette[9]=0x16; - ae->snapshot.gatearray.palette[10]=0x06; - ae->snapshot.gatearray.palette[11]=0x17; - ae->snapshot.gatearray.palette[12]=0x1E; - ae->snapshot.gatearray.palette[13]=0x00; - ae->snapshot.gatearray.palette[14]=0x1F; - ae->snapshot.gatearray.palette[15]=0x0E; - ae->snapshot.gatearray.palette[16]=0x04; - - ae->snapshot.gatearray.multiconfiguration=0x8D; // lower/upper ROM off + mode 1 - ae->snapshot.CPCType=2; /* 6128 */ - ae->snapshot.crtcstate.model=0; /* CRTC 0 */ - ae->snapshot.vsyncdelay=2; - strcpy((char *)ae->snapshot.unused6+3+0x20+8,RASM_VERSION); - /* CRTC default registers */ - ae->snapshot.crtc.registervalue[0]=0x3F; - ae->snapshot.crtc.registervalue[1]=40; - ae->snapshot.crtc.registervalue[2]=46; - ae->snapshot.crtc.registervalue[3]=0x8E; - ae->snapshot.crtc.registervalue[4]=38; - ae->snapshot.crtc.registervalue[6]=25; - ae->snapshot.crtc.registervalue[7]=30; - ae->snapshot.crtc.registervalue[9]=7; - ae->snapshot.crtc.registervalue[12]=0x30; - ae->snapshot.psg.registervalue[7]=0x3F; /* audio mix all channels OFF */ - /* PPI Init */ - ae->snapshot.ppi.control=0x82; - /* standard stack */ - ae->snapshot.registers.HSP=0xC0; - - /* - winape sprintf(symbol_line,"%s #%4X\n",ae->label[i].name,ae->label[i].ptr); - pasmo sprintf(symbol_line,"%s EQU 0%4XH\n",ae->label[i].name,ae->label[i].ptr); - rasm sprintf(symbol_line,"%s #%X B%d\n",ae->wl[ae->label[i].iw].w,ae->label[i].ptr,ae->label[i].ibank>31?0:ae->label[i].ibank); - */ -#if TRACE_PREPRO -printf("paramz\n"); -#endif - if (param && param->labelfilename) { - for (j=0;param->labelfilename[j] && param->labelfilename[j][0];j++) { - rasm_printf(ae,"Label import from [%s]\n",param->labelfilename[j]); - ae->label_filename=param->labelfilename[j]; - ae->label_line=1; - labelines=FileReadLines(param->labelfilename[j]); - i=0; - while (labelines[i]) { - /* upper case */ - for (j=0;labelines[i][j];j++) labelines[i][j]=toupper(labelines[i][j]); - - if ((labelsep1=strstr(labelines[i],": EQU 0"))!=NULL) { - /* sjasm */ - *labelsep1=0; - curlabel.name=labelines[i]; - curlabel.iw=-1; - curlabel.crc=GetCRC(curlabel.name); - curlabel.ptr=strtol(labelsep1+6,NULL,16); - PushLabelLight(ae,&curlabel); - } else if ((labelsep1=strstr(labelines[i]," EQU 0"))!=NULL) { - /* pasmo */ - *labelsep1=0; - curlabel.name=labelines[i]; - curlabel.iw=-1; - curlabel.crc=GetCRC(curlabel.name); - curlabel.ptr=strtol(labelsep1+6,NULL,16); - //ObjectArrayAddDynamicValueConcat((void **)&ae->label,&ae->il,&ae->ml,&curlabel,sizeof(curlabel)); - PushLabelLight(ae,&curlabel); - } else if ((labelsep1=strstr(labelines[i]," "))!=NULL) { - /* winape / rasm */ - if (*(labelsep1+1)=='#') { - *labelsep1=0; - curlabel.name=labelines[i]; - curlabel.iw=-1; - curlabel.crc=GetCRC(curlabel.name); - curlabel.ptr=strtol(labelsep1+2,NULL,16); - //ObjectArrayAddDynamicValueConcat((void **)&ae->label,&ae->il,&ae->ml,&curlabel,sizeof(curlabel)); - PushLabelLight(ae,&curlabel); - } - } - i++; - ae->label_line++; - } - MemFree(labelines); - } - ae->label_filename=NULL; - ae->label_line=0; - } -#if TRACE_PREPRO -printf("init 3\n"); -#endif - /* 32 CPR default roms but 260+ max snapshot RAM pages + one workspace */ - for (i=0;imem,&ae->nbbank,&ae->maxbank,&mem,sizeof(mem)); - } -#if TRACE_PREPRO -printf("nbbank=%d initialised\n",ae->nbbank); -#endif - ae->activebank=BANK_MAX_NUMBER; - ae->maxptr=65536; - for (i=0;i<256;i++) { ae->charset[i]=(unsigned char)i; } - - if (param && param->outputfilename) { - ae->outputfilename=TxtStrDup(param->outputfilename); - } else if (param && param->automatic_radix && param->filename) { - int rilook; - rilook=strlen(param->filename); - ae->outputfilename=TxtStrDup(param->filename); - /* look for extension */ - while (rilook && ae->outputfilename[rilook]!='.') { - /* end of scan with directory reference or nothing found */ - if (ae->outputfilename[rilook]=='/' || ae->outputfilename[rilook]=='\\') rilook=0; else rilook--; - } - if (ae->outputfilename[rilook]=='.') { - ae->outputfilename[rilook]=0; - } - } else { - ae->outputfilename=TxtStrDup("rasmoutput"); - } - /* si on est en ligne de commande ET que le fichier n'est pas trouvé */ - if (param && param->filename && !FileExists(param->filename)) { - char *LTryExtension[]={".asm",".z80",".o",".dam",".mxm",".txt", - ".ASM",".Z80",".O",".DAM",".MXM",".TXT",NULL}; - - int iguess=1; - l=strlen(param->filename); - filename=MemRealloc(param->filename,l+6); - /* si le nom du fichier termine par un . on n'ajoute que l'extension, sinon on l'ajoute avec le . */ - if (param->filename[l-1]=='.') strcat(param->filename,"asm"); else strcat(param->filename,".asm"); - - while (!FileExists(param->filename) && LTryExtension[iguess]!=NULL) { - TxtReplace(param->filename,LTryExtension[iguess-1],LTryExtension[iguess],0); /* no realloc with this */ - if (!FileExists(param->filename)) { - param->filename[l]=0; - } - iguess++; - } - } - - if (param && param->filename && !FileExists(param->filename)) { - rasm_printf(ae,"Cannot find file [%s]\n",param->filename); - exit(-1802); - } - - if (param) rasm_printf(ae,KAYGREEN"Pre-processing [%s]\n",param->filename); - for (nbinstruction=0;instruction[nbinstruction].mnemo[0];nbinstruction++); - qsort(instruction,nbinstruction,sizeof(struct s_asm_keyword),cmpkeyword); - for (i=0;i<256;i++) { ae->fastmatch[i]=-1; } - for (i=0;ifastmatch[(int)instruction[i].mnemo[0]]==-1) ae->fastmatch[(int)instruction[i].mnemo[0]]=i; } - for (i=0;CharWord[i];i++) {Automate[((int)CharWord[i])&0xFF]=1;} - /* separators */ - Automate[' ']=2; - Automate[',']=2; - Automate['\t']=2; - /* end of line */ - Automate[':']=3; /* les 0x0A et 0x0D seront deja  remplaces en ':' */ - /* expression */ - Automate['=']=4; /* on stocke l'emplacement de l'egalite */ - Automate['<']=4; /* ou des operateurs */ - Automate['>']=4; /* d'evaluation */ - Automate['!']=4; - - StateMachineResizeBuffer(&w,256,&mw); - StateMachineResizeBuffer(&bval,256,&sval); - StateMachineResizeBuffer(&qval,256,&sqval); - w[0]=0; - bval[0]=0; - qval[0]=0; - -#if TRACE_PREPRO -printf("read file/flux\n"); -#endif -#if TRACE_GENERALE -printf("-read/flux\n"); -#endif - - if (!ae->flux) { - zelines=FileReadLines(filename); - FieldArrayAddDynamicValueConcat(&ae->filename,&ae->ifile,&ae->maxfile,filename); - } else { - int flux_nblines=0; - int flux_curpos; - - /* copie des données */ - for (i=0;iflux_curpos) { - zelines[flux_nblines]=MemMalloc(i-flux_curpos+1); - memcpy(zelines[flux_nblines],datain+flux_curpos,i-flux_curpos); - zelines[flux_nblines][i-flux_curpos]=0; - flux_nblines++; - } - /* terminator */ - zelines[flux_nblines]=NULL; - - /* en mode flux on prend le repertoire courant en reference */ - FieldArrayAddDynamicValueConcat(&ae->filename,&ae->ifile,&ae->maxfile,CURRENT_DIR); - } - -#if TRACE_PREPRO -printf("remove comz, do includes\n"); -#endif -#if TRACE_GENERALE -printf("-comz/include\n"); -#endif - EarlyPrepSrc(ae,zelines,ae->filename[ae->ifile-1]); - - for (i=0;zelines[i];i++) { - curlisting.ifile=0; - curlisting.iline=i+1; - curlisting.listing=zelines[i]; - ObjectArrayAddDynamicValueConcat((void**)&listing,&ilisting,&maxlisting,&curlisting,sizeof(curlisting)); - } - MemFree(zelines); - - /* on s'assure que la derniere instruction est prise en compte a peu de frais */ - if (ilisting) { - datalen=strlen(listing[ilisting-1].listing); - listing[ilisting-1].listing=MemRealloc(listing[ilisting-1].listing,datalen+2); - listing[ilisting-1].listing[datalen]=':'; - listing[ilisting-1].listing[datalen+1]=0; - } - - waiting_quote=quote_type=0; - l=idx=0; - while (l2 && strncmp(&listing[l].listing[idx-3],"AF'",3)==0) { - /* rien */ - } else if (c=='"' || c=='\'') { - if (!quote_type) { - quote_type=c; - lquote=l; - } else { - if (c==quote_type) { - quote_type=0; - } - } - } - - if (waiting_quote) { - /* expecting quote and nothing else */ - switch (waiting_quote) { - case 1: - if (c==quote_type) waiting_quote=2; - break; - case 2: - if (!quote_type) { - waiting_quote=3; - qval[iqval]=0; - } else { - qval[iqval++]=c; - StateMachineResizeBuffer(&qval,iqval,&sqval); - qval[iqval]=0; - } - } - if (waiting_quote==3) { - if (incbin) { - int fileok=0,ilookfile; - /* qval contient le nom du fichier a lire */ - filename_toread=MergePath(ae,ae->filename[listing[l].ifile],qval); - if (FileExists(filename_toread)) { - fileok=1; - } else { - for (ilookfile=0;ilookfileipath && !fileok;ilookfile++) { - filename_toread=MergePath(ae,ae->includepath[ilookfile],qval); - if (FileExists(filename_toread)) { - fileok=1; - } - } - } - - curhexbin.filename=TxtStrDup(filename_toread); - curhexbin.crunch=crunch; - if (fileok) { - /* lecture */ - curhexbin.rawlen=curhexbin.datalen=FileGetSize(filename_toread); - curhexbin.data=MemMalloc(curhexbin.datalen*1.3+10); - #if TRACE_PREPRO - switch (crunch) { - case 0:rasm_printf(ae,KBLUE"incbin [%s] size=%d\n",filename_toread,curhexbin.datalen);break; - case 4:rasm_printf(ae,KBLUE"inclz4 [%s] size=%d\n",filename_toread,curhexbin.datalen);break; - case 7:rasm_printf(ae,KBLUE"incsx7 [%s] size=%d\n",filename_toread,curhexbin.datalen);break; - case 8:rasm_printf(ae,KBLUE"incexo [%s] size=%d\n",filename_toread,curhexbin.datalen);break; - case 88:rasm_printf(ae,KBLUE"incexb [%s] size=%d\n",filename_toread,curhexbin.datalen);break; - case 48:rasm_printf(ae,KBLUE"incl48 [%s] size=%d\n",filename_toread,curhexbin.datalen);break; - case 49:rasm_printf(ae,KBLUE"incl49 [%s] size=%d\n",filename_toread,curhexbin.datalen);break; - default:rasm_printf(ae,KBLUE"invalid crunch state!\n");exit(-42); - } - #endif - if (FileReadBinary(filename_toread,(char*)curhexbin.data,curhexbin.datalen)!=curhexbin.datalen) { - rasm_printf(ae,"read error on %s",filename_toread); - exit(2); - } - FileReadBinaryClose(filename_toread); - switch (crunch) { - #ifndef NO_3RD_PARTIES - case 4: - newdata=LZ4_crunch(curhexbin.data,curhexbin.datalen,&curhexbin.datalen); - MemFree(curhexbin.data); - curhexbin.data=newdata; - #if TRACE_PREPRO - rasm_printf(ae,KVERBOSE"crunched with LZ4 into %d byte(s)\n",curhexbin.datalen); - #endif - break; - case 7: - { - size_t slzlen; - newdata=ZX7_compress(optimize(curhexbin.data, curhexbin.datalen), curhexbin.data, curhexbin.datalen, &slzlen); - curhexbin.datalen=slzlen; - MemFree(curhexbin.data); - curhexbin.data=newdata; - #if TRACE_PREPRO - rasm_printf(ae,KVERBOSE"crunched with ZX7 into %d byte(s)\n",curhexbin.datalen); - #endif - } - break; - case 8: - rasm_printf(ae,KWARNING"Exomizer is crunching %.1fkb this may take a while, be patient...\n",curhexbin.datalen/1024.0); - newdata=Exomizer_crunch(curhexbin.data,curhexbin.datalen,&curhexbin.datalen); - MemFree(curhexbin.data); - curhexbin.data=newdata; - #if TRACE_PREPRO - rasm_printf(ae,KVERBOSE"crunched with Exomizer into %d byte(s)\n",curhexbin.datalen); - #endif - break; - #endif - case 48: - newdata=LZ48_crunch(curhexbin.data,curhexbin.datalen,&curhexbin.datalen); - MemFree(curhexbin.data); - curhexbin.data=newdata; - #if TRACE_PREPRO - rasm_printf(ae,KVERBOSE"crunched with LZ48 into %d byte(s)\n",curhexbin.datalen); - #endif - break; - case 49: - newdata=LZ49_crunch(curhexbin.data,curhexbin.datalen,&curhexbin.datalen); - MemFree(curhexbin.data); - curhexbin.data=newdata; - #if TRACE_PREPRO - rasm_printf(ae,KVERBOSE"crunched into with LZ49 %d byte(s)\n",curhexbin.datalen); - #endif - break; - default:break; - } - } else { - /* TAG + info */ - curhexbin.datalen=-1; - curhexbin.data=MemMalloc(2); - /* not yet an error, we will know later when executing the code */ - } - ObjectArrayAddDynamicValueConcat((void**)&ae->hexbin,&ae->ih,&ae->mh,&curhexbin,sizeof(curhexbin)); - /* insertion */ - le=strlen(listing[l].listing); - - newlistingline=MemMalloc(le+32); - memcpy(newlistingline,listing[l].listing,rewrite); - rewrite+=sprintf(newlistingline+rewrite,"HEXBIN #%X",ae->ih-1); - strcat(newlistingline+rewrite,listing[l].listing+idx); - idx=rewrite; - MemFree(listing[l].listing); - listing[l].listing=newlistingline; - incbin=0; - } else if (include) { - /* qval contient le nom du fichier a lire */ - int fileok=0,ilookfile; - /* qval contient le nom du fichier a lire */ - filename_toread=MergePath(ae,ae->filename[listing[l].ifile],qval); - if (FileExists(filename_toread)) { - fileok=1; - } else { - for (ilookfile=0;ilookfileipath && !fileok;ilookfile++) { - filename_toread=MergePath(ae,ae->includepath[ilookfile],qval); - if (FileExists(filename_toread)) { - fileok=1; - } - } - } - - if (fileok) { - int newi,newj; - #if TRACE_PREPRO - rasm_printf(ae,KBLUE"include [%s]\n",filename_toread); - #endif - - /* lecture */ - listing_include=FileReadLines(filename_toread); - FieldArrayAddDynamicValueConcat(&ae->filename,&ae->ifile,&ae->maxfile,filename_toread); - /* virer les commentaires + pré-traitement */ - EarlyPrepSrc(ae,listing_include,ae->filename[ae->ifile-1]); - - /* split de la ligne en cours + suppression de l'instruction include */ - PreProcessingSplitListing(&listing,&ilisting,&maxlisting,l,rewrite,idx); - /* insertion des nouvelles lignes + reference fichier + numeros de ligne */ - PreProcessingInsertListing(&listing,&ilisting,&maxlisting,l,listing_include,ae->ifile-1); - - MemFree(listing_include); /* free le tableau mais pas les lignes */ - listing_include=NULL; - idx=0; /* on reste sur la meme ligne mais on se prepare a relire du caractere 0! */ - } else { - /* TAG + info */ - curhexbin.filename=TxtStrDup(filename_toread); - curhexbin.datalen=-2; - curhexbin.data=MemMalloc(2); - /* not yet an error, we will know later when executing the code */ - ObjectArrayAddDynamicValueConcat((void**)&ae->hexbin,&ae->ih,&ae->mh,&curhexbin,sizeof(curhexbin)); - /* insertion */ - le=strlen(listing[l].listing); - newlistingline=MemMalloc(le+32); - memcpy(newlistingline,listing[l].listing,rewrite); - rewrite+=sprintf(newlistingline+rewrite,"HEXBIN #%X",ae->ih-1); - strcat(newlistingline+rewrite,listing[l].listing+idx); - idx=rewrite; - MemFree(listing[l].listing); - listing[l].listing=newlistingline; - } - include=0; - } - waiting_quote=0; - qval[0]=0; - iqval=0; - } - } else { - /* classic behaviour */ - - /* looking for include/incbin */ - if (((c>='A' && c<='Z') || (c>='0' && c<='9') || c=='@' || c=='_')&& !quote_type) { - bval[ival++]=c; - StateMachineResizeBuffer(&bval,ival,&sval); - bval[ival]=0; - } else { - if (strcmp(bval,"INCLUDE")==0) { - include=1; - waiting_quote=1; - rewrite=idx-7-1; - /* quote right after keyword */ - if (c==quote_type) { - waiting_quote=2; - } - } else if (strcmp(bval,"READ")==0) { - include=1; - waiting_quote=1; - rewrite=idx-4-1; - /* quote right after keyword */ - if (c==quote_type) { - waiting_quote=2; - } - } else if (strcmp(bval,"INCLZ4")==0) { - incbin=1; - crunch=4; - waiting_quote=1; - rewrite=idx-6-1; - /* quote right after keyword */ - if (c==quote_type) { - waiting_quote=2; - } - } else if (strcmp(bval,"INCEXB")==0) { - incbin=1; - crunch=88; - waiting_quote=1; - rewrite=idx-6-1; - /* quote right after keyword */ - if (c==quote_type) { - waiting_quote=2; - } - } else if (strcmp(bval,"INCEXO")==0) { - incbin=1; - crunch=8; - waiting_quote=1; - rewrite=idx-6-1; - /* quote right after keyword */ - if (c==quote_type) { - waiting_quote=2; - } - } else if (strcmp(bval,"INCZX7")==0) { - incbin=1; - crunch=7; - waiting_quote=1; - rewrite=idx-6-1; - /* quote right after keyword */ - if (c==quote_type) { - waiting_quote=2; - } - } else if (strcmp(bval,"INCL48")==0) { - incbin=1; - crunch=48; - waiting_quote=1; - rewrite=idx-6-1; - /* quote right after keyword */ - if (c==quote_type) { - waiting_quote=2; - } - } else if (strcmp(bval,"INCL49")==0) { - incbin=1; - crunch=49; - waiting_quote=1; - rewrite=idx-6-1; - /* quote right after keyword */ - if (c==quote_type) { - waiting_quote=2; - } - } else if (strcmp(bval,"INCBIN")==0) { - incbin=1; - crunch=0; - waiting_quote=1; - rewrite=idx-6-1; - /* quote right after keyword */ - if (c==quote_type) { - waiting_quote=2; - } - } else if (strcmp(bval,"INCWAV")==0) { - incbin=1; - crunch=0; - waiting_quote=1; - rewrite=idx-6-1; - /* quote right after keyword */ - if (c==quote_type) { - waiting_quote=2; - } - } else if (strcmp(bval,"WHILE")==0) { - /* remplir la structure repeat_index */ - windex.ol=listing[l].iline; - windex.oidx=idx; - windex.ifile=ae->ifile-1; - ObjectArrayAddDynamicValueConcat((void**)&TABwindex,&nwi,&mwi,&windex,sizeof(windex)); - } else if (strcmp(bval,"REPEAT")==0) { - /* remplir la structure repeat_index */ - rindex.ol=listing[l].iline; - rindex.oidx=idx; - rindex.ifile=ae->ifile-1; - ObjectArrayAddDynamicValueConcat((void**)&TABrindex,&nri,&mri,&rindex,sizeof(rindex)); - } else if (strcmp(bval,"WEND")==0) { - /* retrouver la structure repeat_index correspondant a l'ouverture */ - for (wi=nwi-1;wi>=0;wi--) { - if (TABwindex[wi].cl==-1) { - TABwindex[wi].cl=c; - TABwindex[wi].cidx=idx; - break; - } - } - if (wi==-1) { - MakeError(ae,ae->filename[listing[l].ifile],listing[l].iline,"WEND refers to unknown WHILE\n"); - //exit(1); - } - } else if (strcmp(bval,"REND")==0 || strcmp(bval,"UNTIL")==0) { - /* retrouver la structure repeat_index correspondant a l'ouverture */ - for (ri=nri-1;ri>=0;ri--) { - if (TABrindex[ri].cl==-1) { - TABrindex[ri].cl=c; - TABrindex[ri].cidx=idx; - break; - } - } - if (ri==-1) { - MakeError(ae,ae->filename[listing[l].ifile],listing[l].iline,"%s refers to unknown REPEAT\n",bval); - //exit(1); - } - - } - bval[0]=0; - ival=0; - } - } - } -#if TRACE_PREPRO -printf("check quotes and repeats\n"); -#endif - if (quote_type) { - MakeError(ae,ae->filename[listing[lquote].ifile],listing[lquote].iline,"quote opened was not closed\n"); - //exit(1); - } - - /* repeat expansion check */ - for (ri=0;rifilename[TABrindex[ri].ifile],TABrindex[ri].ol,"REPEAT was not closed\n"); - } - } - - /* creer une liste de mots */ - curw.w=TxtStrDup("BEGIN"); - curw.l=0; - curw.ifile=0; - curw.t=1; - curw.e=0; - ObjectArrayAddDynamicValueConcat((void**)&wordlist,&nbword,&maxword,&curw,sizeof(curw)); - - /* pour les calculs d'adresses avec IX et IY on enregistre deux variables bidons du meme nom */ - curw.e=2; - curw.w=TxtStrDup("IX~0"); - ObjectArrayAddDynamicValueConcat((void**)&wordlist,&nbword,&maxword,&curw,sizeof(curw)); - curw.w=TxtStrDup("IY~0"); - ObjectArrayAddDynamicValueConcat((void**)&wordlist,&nbword,&maxword,&curw,sizeof(curw)); - curw.e=0; - -#if TRACE_PREPRO - l=0; - while (l31?c:'.',Automate[((int)c)&0xFF]); -#endif - switch (Automate[((int)c)&0xFF]) { - case 0: - MakeError(ae,ae->filename[listing[l].ifile],listing[l].iline,"invalid char '%c' (%d) char %d\n",c,c,idx); -#if TRACE_PREPRO -printf("c='%c' automate[c]=%d\n",c>31?c:'.',Automate[((int)c)&0xFF]); -#endif - exit(0); - break; - case 1: - if (c=='\'' && idx>2 && strncmp(&listing[l].listing[idx-3],"AF'",3)==0) { - w[lw++]=c; - StateMachineResizeBuffer(&w,lw,&mw); - w[lw]=0; - break; - } else if (c=='\'' || c=='"') { - quote_type=c; - /* debut d'une quote, on finalise le mot -> POURQUOI DONC? */ - //idx--; -#if TRACE_PREPRO -printf("quote\n"); -#endif - /* on finalise le mot si on est en début d'une nouvelle instruction ET que c'est un SAVE */ - if (strcmp(w,"SAVE")==0) { - idx--; - } else { - w[lw++]=c; - StateMachineResizeBuffer(&w,lw,&mw); - w[lw]=0; - break; - } - } else { - if (c!=' ' && c!='\t') { - w[lw++]=c; - StateMachineResizeBuffer(&w,lw,&mw); - w[lw]=0; - } else { - /* Winape/Maxam operator compatibility on expressions */ -#if TRACE_PREPRO -printf("1/2 winape maxam operator test for [%s]\n",w+ispace); -#endif - if (texpr) { - if (strcmp(w+ispace,"AND")==0) { - w[ispace]='&'; - lw=ispace+1; - } else if (strcmp(w+ispace,"OR")==0) { -#if TRACE_PREPRO -printf("conversion OR vers |\n"); -#endif - w[ispace]='|'; - lw=ispace+1; - } else if (strcmp(w+ispace,"MOD")==0) { - w[ispace]='m'; - lw=ispace+1; - } else if (strcmp(w+ispace,"XOR")==0) { - w[ispace]='^'; - lw=ispace+1; - } else if (strcmp(w+ispace,"%")==0) { - w[ispace]='m'; - lw=ispace+1; - } - } - ispace=lw; - } - break; - } - case 2: - /* separator (space, tab, comma) */ -#if TRACE_PREPRO -printf("*** separator='%c'\n",c); -#endif - - /* patch argument suit une expression d'évaluation (ASSERT) */ - if (c==',') hadcomma=1; - - if (lw) { - w[lw]=0; - if (texpr && !wordlist[nbword-1].t && wordlist[nbword-1].e && !hadcomma) { - /* pour compatibilite winape avec AND,OR,XOR */ -#if TRACE_PREPRO -printf("2/2 winape maxam operator test for expression [%s]\n",w+ispace); -#endif - if (strcmp(w,"AND")==0) { - wtmp=TxtStrDup("&"); - } else if (strcmp(w,"OR")==0) { - wtmp=TxtStrDup("|"); - } else if (strcmp(w,"XOR")==0) { - wtmp=TxtStrDup("^"); - } else if (strcmp(w,"%")==0) { - wtmp=TxtStrDup("m"); - } else { - wtmp=TxtStrDup(w); - } - /* on concatène le nouveau mot à l'expression */ - nbword--; - lw=0; - for (li=0;wordlist[nbword].w[li];li++) { - w[lw++]=wordlist[nbword].w[li]; - StateMachineResizeBuffer(&w,lw,&mw); - } - w[lw]=0; - MemFree(wordlist[nbword].w); - - for (li=0;wtmp[li];li++) { - w[lw++]=wtmp[li]; - StateMachineResizeBuffer(&w,lw,&mw); - } - w[lw]=0; - MemFree(wtmp); - /* et on modifie l'automate pour la suite! */ - Automate[' ']=1; - Automate['\t']=1; - ispace=lw; - } else if (strcmp(w,"EQU")==0) { - /* il y avait un mot avant alors on va reorganiser la ligne */ - nbword--; - lw=0; - for (li=0;wordlist[nbword].w[li];li++) { - w[lw++]=wordlist[nbword].w[li]; - StateMachineResizeBuffer(&w,lw,&mw); - } - MemFree(wordlist[nbword].w); - curw.e=lw+1; - /* on ajoute l'egalite d'alias*/ - w[lw++]='~'; - StateMachineResizeBuffer(&w,lw,&mw); - w[lw]=0; - Automate[' ']=1; - Automate['\t']=1; - ispace=lw; - texpr=1; - } else { - curw.w=TxtStrDup(w); - curw.l=listing[l].iline; - curw.ifile=listing[l].ifile; - curw.t=0; -#if TRACE_PREPRO -if (curw.w[0]=='=') { - printf("(1) bug prout\n"); - exit(1); -} -printf("ajout du mot [%s]\n",curw.w); -#endif - ObjectArrayAddDynamicValueConcat((void**)&wordlist,&nbword,&maxword,&curw,sizeof(curw)); - //texpr=0; /* reset expr */ - curw.e=0; - lw=0; - w[lw]=0; - - /* match keyword? then next spaces will be ignored*/ - if (macro_trigger) { - struct s_macro_fast curmacrofast; - Automate[' ']=1; - Automate['\t']=1; - ispace=0; - texpr=1; -#if TRACE_PREPRO -printf("macro trigger w=[%s]\n",curw.w); -#endif - /* add macro name to instruction pool for preprocessor but not struct or write */ - if (macro_trigger=='M') { - curmacrofast.mnemo=curw.w; - curmacrofast.crc=GetCRC(curw.w); - ObjectArrayAddDynamicValueConcat((void**)&MacroFast,&idxmacrofast,&maxmacrofast,&curmacrofast,sizeof(struct s_macro_fast)); - } - macro_trigger=0; - } else { - int keymatched=0; - if ((ifast=ae->fastmatch[(int)curw.w[0]])!=-1) { - while (instruction[ifast].mnemo[0]==curw.w[0]) { - if (strcmp(instruction[ifast].mnemo,curw.w)==0) { - keymatched=1; - if (strcmp(curw.w,"MACRO")==0 || strcmp(curw.w,"STRUCT")==0 || strcmp(curw.w,"WRITE")==0) { -/* @@TODO AS80 compatibility patch!!! */ - macro_trigger=curw.w[0]; - } else { - Automate[' ']=1; - Automate['\t']=1; - ispace=0; - /* instruction en cours, le reste est a interpreter comme une expression */ -#if TRACE_PREPRO -printf("instruction en cours\n"); -#endif - texpr=1; - } - break; - } - ifast++; - } - } - if (!keymatched) { - int macrocrc; - macrocrc=GetCRC(curw.w); - for (keymatched=0;keymatchedfilename[listing[l].ifile],listing[l].iline,"empty parameter\n"); - } - } - break; - case 3: - /* fin de ligne, on remet l'automate comme il faut */ -#if TRACE_PREPRO -printf("EOL\n"); -#endif - macro_trigger=0; - Automate[' ']=2; - Automate['\t']=2; - ispace=0; - texpr=0; - /* si le mot lu a plus d'un caractère */ - if (lw) { - if (!wordlist[nbword-1].t && (wordlist[nbword-1].e || w[0]=='=') && !hadcomma) { - /* cas particulier d'ecriture libre */ - /* bugfix inhibition 19.06.2018 */ - /* ajout du terminateur? */ - w[lw]=0; -#if TRACE_PREPRO -printf("nbword=%d w=[%s] ->",nbword,w);fflush(stdout); -#endif - nbword--; - wordlist[nbword].w=MemRealloc(wordlist[nbword].w,strlen(wordlist[nbword].w)+lw+1); - strcat(wordlist[nbword].w,w); -#if TRACE_PREPRO -printf("%s\n",wordlist[nbword].w); -#endif - /* on change de type! */ - wordlist[nbword].t=1; - //ObjectArrayAddDynamicValueConcat((void**)&wordlist,&nbword,&maxword,&curw,sizeof(curw)); - curw.e=0; - lw=0; - w[lw]=0; - } else if (nbword && strcmp(w,"EQU")==0) { - /* il y avait un mot avant alors on va reorganiser la ligne */ - nbword--; - lw=0; - for (li=0;wordlist[nbword].w[li];li++) { - w[lw++]=wordlist[nbword].w[li]; - StateMachineResizeBuffer(&w,lw,&mw); - w[lw]=0; - } - MemFree(wordlist[nbword].w); - /* on ajoute l'egalite ou comparaison! */ - curw.e=lw+1; - w[lw++]='='; - StateMachineResizeBuffer(&w,lw,&mw); - w[lw]=0; - Automate[' ']=1; - Automate['\t']=1; - } else { - /* mot de fin de ligne, à priori pas une expression */ - curw.w=TxtStrDup(w); - curw.l=listing[l].iline; - curw.ifile=listing[l].ifile; - curw.t=1; -#if TRACE_PREPRO -printf("mot de fin de ligne = [%s]\n",curw.w); -if (curw.w[0]=='=') { - printf("(3) bug prout\n"); - exit(1); -} -#endif - ObjectArrayAddDynamicValueConcat((void**)&wordlist,&nbword,&maxword,&curw,sizeof(curw)); - curw.e=0; - lw=0; - w[lw]=0; - hadcomma=0; - } - } else { - /* sinon c'est le précédent qui était terminateur d'instruction */ - wordlist[nbword-1].t=1; - w[lw]=0; - } - hadcomma=0; - break; - case 4: -#if TRACE_PREPRO -printf("expr operator=%c\n",c); -#endif - /* expression/condition */ - texpr=1; - if (lw) { - Automate[' ']=1; - Automate['\t']=1; - if (!curw.e) { - curw.e=lw+1; - w[lw++]=c; - StateMachineResizeBuffer(&w,lw,&mw); - w[lw]=0; - } else { - w[lw++]=c; - StateMachineResizeBuffer(&w,lw,&mw); - w[lw]=0; - } - } else { - /* 2018.06.06 évolution sur le ! (not) */ -#if TRACE_PREPRO -printf("*** operateur commence le mot\n"); -printf("mot precedent=[%s] t=%d\n",wordlist[nbword-1].w,wordlist[nbword-1].t); -#endif - if (hadcomma && c=='!') { - /* on peut commencer un argument par un NOT */ - w[lw++]=c; - StateMachineResizeBuffer(&w,lw,&mw); - w[lw]=0; - /* automate déjà modifié rien de plus */ - } else if (!wordlist[nbword-1].t) { - /* il y avait un mot avant alors on va reorganiser la ligne */ - /* patch NOT -> SAUF si c'est une directive */ - int keymatched=0; - if ((ifast=ae->fastmatch[(int)wordlist[nbword-1].w[0]])!=-1) { - while (instruction[ifast].mnemo[0]==wordlist[nbword-1].w[0]) { - if (strcmp(instruction[ifast].mnemo,wordlist[nbword-1].w)==0) { - keymatched=1; - break; - } - ifast++; - } - } - if (!keymatched) { - int macrocrc; - macrocrc=GetCRC(wordlist[nbword-1].w); - for (i=0;ifilename[listing[l].ifile],listing[l].iline,"cannot start expression with '=','!','<','>'\n"); - } - } - break; - default: - rasm_printf(ae,KERROR"Internal error (Automate wrong value=%d)\n",Automate[c]); - exit(-1); - } - } else { - /* lecture inconditionnelle de la quote */ -#if TRACE_PREPRO -printf("quote[%d]=%c\n",lw,c); -#endif - w[lw++]=c; - StateMachineResizeBuffer(&w,lw,&mw); - w[lw]=0; - if (!escape_code) { - if (c=='\\') escape_code=1; - if (lw>1 && c==quote_type) { - quote_type=0; - } - } else { - escape_code=0; - } - } - } - -#if TRACE_PREPRO -printf("END\n"); -#endif - - curw.w="END"; - curw.l=0; - curw.t=2; - curw.ifile=0; - ObjectArrayAddDynamicValueConcat((void**)&wordlist,&nbword,&maxword,&curw,sizeof(curw)); -#if TRACE_PREPRO - rasm_printf(ae,KVERBOSE"wordlist contains %d element%s\n",nbword,nbword>1?"s":""); -#endif - ae->nbword=nbword; - - /* switch words for macro declaration with AS80 & UZ80 */ - if (param && param->as80) { - for (l=0;lwl=wordlist; - if (param) { - MemFree(param->filename); - } - if (MacroFast) MemFree(MacroFast); - if (TABwindex) MemFree(TABwindex); - if (TABrindex) MemFree(TABrindex); -#if TRACE_PREPRO -printf("return ae\n"); -#endif - return ae; -} - -int Rasm(struct s_parameter *param) -{ - #undef FUNC - #define FUNC "Rasm" - - struct s_assenv *ae=NULL; - - /* read and preprocess source */ - ae=PreProcessing(param->filename,0,NULL,0,param); - /* assemble */ - return Assemble(ae,NULL,NULL,NULL); -} - -/* fonction d'export */ - -int RasmAssemble(const char *datain, int lenin, unsigned char **dataout, int *lenout) -{ - struct s_assenv *ae=NULL; - - if (lenout) *lenout=0; - ae=PreProcessing(NULL,1,datain,lenin,NULL); - return Assemble(ae,dataout,lenout,NULL); -} - -int RasmAssembleInfo(const char *datain, int lenin, unsigned char **dataout, int *lenout, struct s_rasm_info **debug) -{ - struct s_assenv *ae=NULL; - int ret; - - ae=PreProcessing(NULL,1,datain,lenin,NULL); - ret=Assemble(ae,dataout,lenout,debug); - return ret; -} - - -#define AUTOTEST_PAGELABELGEN "buildsna: bank: cpt=5: ld bc,{page}miam{cpt}: bank cpt: nop: miam{cpt} nop: assert {page}miam{cpt}==0x7FC5 " - -#define AUTOTEST_NOINCLUDE "truc equ 0:if truc:include'bite':endif:nop" - -#define AUTOTEST_SETINSIDE "ld hl,0=0xC9FB" - -#define AUTOTEST_OPERATOR_CONVERSION "ld hl,10 OR 20:ld a,40 and 10:ld bc,5 MOD 2:ld a,(ix+45 xor 45)" - -#define AUTOTEST_OPERATOR_MODULO "revar=46: devar=5 : var=46%5 : assert var==1: var=46 % 5 : assert var==1: var=46 mod 5 : assert var==1:" \ - "var=revar%5 : assert var==1: var=revar%devar : assert var==1: var=46%devar : assert var==1: var=revar % 5 : assert var==1:" \ - "var=revar % devar : assert var==1: var=46 % devar : assert var==1: var=revar % %101 : assert var==1: var=revar%%101 : assert var==1: nop" - -#define AUTOTEST_UNDEF "mavar=10: ifdef mavar: undef mavar: endif: ifdef mavar: fail 'undef did not work': endif:nop " - -#define AUTOTEST_INSTRMUSTFAILED "ld a,b,c:ldi a: ldir bc:exx hl,de:exx de:ex bc,hl:ex hl,bc:ex af,af:ex hl,hl:ex hl:exx hl: "\ - "neg b:push b:push:pop:pop c:sub ix:add ix:add:sub:di 2:ei 3:ld i,c:ld r,e:rl:rr:rlca a:sla:sll:"\ - "ldd e:lddr hl:adc ix:adc b,a:xor 12,13:xor b,1:xor:or 12,13:or b,1:or:and 12,13:and b,1:and:inc:dec" - -#define AUTOTEST_VIRGULE "defb 5,5,,5" -#define AUTOTEST_VIRGULE2 "print '5,,5':nop" - -#define AUTOTEST_OVERLOADMACPRM "macro test,idx: defb idx:endm:macro test2,idx:defb {idx}:endm:repeat 2,idx:test idx-1:test2 idx-1:rend" - -#define AUTOTEST_IFDEFMACRO "macro test:nop:endm:ifndef test:error:else:test:endif:ifdef test:test:else:error:endif:nop" - -#define AUTOTEST_PRINTVAR "label1: macro test, param: print 'param {param}', {hex}{param}: endm:: test label1: nop" - -#define AUTOTEST_PRINTSPACE "idx=5: print 'grouik { idx + 3 } ':nop" - -#define AUTOTEST_NOT "myvar=10:myvar=10+myvar:if 5!=3:else:print glop:endif:ifnot 5:print glop:else:endif:" \ - "ifnot 0:else:print glop:endif:if !(5):print glop:endif:if !(0):else:print glop:endif:" \ - "ya=!0:if ya==1:else:print glop:endif:if !5:print glop:endif:ya = 0:ya =! 0:if ya == 1:" \ - "else:print glop:endif:if ! 5:print glop:endif:if 1-!( !0 && !0):else:print glop:endif:nop" - - -#define AUTOTEST_MACRO "macro glop:@glop:ld hl,@next:djnz @glop:@next:mend:macro glop2:@glop:glop:ld hl,@next:djnz @glop:glop:" \ - "@next:mend:cpti=0:repeat:glop:cpt=0:glop:repeat:glop2:repeat 1:@glop:dec a:ld hl,@next:glop2:glop2:" \ - "jr nz,@glop:@next:rend:cpt=cpt+1:glop2:until cpt<3:cpti=cpti+1:glop2:until cpti<3" - -#define AUTOTEST_MACRO_ADV "idx=10:macro mac2 param1,param2:ld hl,{param1}{idx+10}{param2}:{param1}{idx+10}{param2}:djnz {param1}{idx+10}{param2}:mend: " \ - "mac2 label,45:mac2 glop,10:djnz glop2010:jp label2045" - -#define AUTOTEST_MACROPAR "macro unemac, param1, param2:defb '{param1}':defb {param2}:mend:unemac grouik,'grouik'" - -#define AUTOTEST_OPCODES "nop::ld bc,#1234::ld (bc),a::inc bc:inc b:dec b:ld b,#12:rlca:ex af,af':add hl,bc:ld a,(bc):dec bc:" \ - "inc c:dec c:ld c,#12:rrca::djnz $:ld de,#1234:ld (de),a:inc de:inc d:dec d:ld d,#12:rla:jr $:" \ - "add hl,de:ld a,(de):dec de:inc e:dec e:ld e,#12:rra::jr nz,$:ld hl,#1234:ld (#1234),hl:inc hl:inc h:" \ - "dec h:ld h,#12:daa:jr z,$:add hl,hl:ld hl,(#1234):dec hl:inc l:dec l:ld l,#12:cpl::jr nc,$:" \ - "ld sp,#1234:ld (#1234),a:inc sp:inc (hl):dec (hl):ld (hl),#12:scf:jr c,$:add hl,sp:ld a,(#1234):" \ - "dec sp:inc a:dec a:ld a,#12:ccf::ld b,b:ld b,c:ld b,d:ld b,e:ld b,h:ld b,l:ld b,(hl):ld b,a:ld c,b:" \ - "ld c,c:ld c,d:ld c,e:ld c,h:ld c,l:ld c,(hl):ld c,a::ld d,b:ld d,c:ld d,d:ld d,e:ld d,h:ld d,l:" \ - "ld d,(hl):ld d,a:ld e,b:ld e,c:ld e,d:ld e,e:ld e,h:ld e,l:ld e,(hl):ld e,a::ld h,b:ld h,c:ld h,d:" \ - "ld h,e:ld h,h:ld h,l:ld h,(hl):ld h,a:ld l,b:ld l,c:ld l,d:ld l,e:ld l,h:ld l,l:ld l,(hl):ld l,a::" \ - "ld (hl),b:ld (hl),c:ld (hl),d:ld (hl),e:ld (hl),h:ld (hl),l:halt:ld (hl),a:ld a,b:ld a,c:ld a,d:" \ - "ld a,e:ld a,h:ld a,l:ld a,(hl):ld a,a::add b:add c:add d:add e:add h:add l:add (hl):add a:adc b:" \ - "adc c:adc d:adc e:adc h:adc l:adc (hl):adc a::sub b:sub c:sub d:sub e:sub h:sub l:sub (hl):sub a:" \ - "sbc b:sbc c:sbc d:sbc e:sbc h:sbc l:sbc (hl):sbc a::and b:and c:and d:and e:and h:and l:and (hl):" \ - "and a:xor b:xor c:xor d:xor e:xor h:xor l:xor (hl):xor a::or b:or c:or d:or e:or h:or l:or (hl):" \ - "or a:cp b:cp c:cp d:cp e:cp h:cp l:cp (hl):cp a::ret nz:pop bc:jp nz,#1234:jp #1234:call nz,#1234:" \ - "push bc:add #12:rst 0:ret z:ret:jp z,#1234:nop:call z,#1234:call #1234:adc #12:rst 8::ret nc:pop de:" \ - "jp nc,#1234:out (#12),a:call nc,#1234:push de:sub #12:rst #10:ret c:exx:jp c,#1234:in a,(#12):" \ - "call c,#1234:nop:sbc #12:rst #18::ret po:pop hl:jp po,#1234:ex (sp),hl:call po,#1234:push hl:" \ - "and #12:rst #20:ret pe:jp (hl):jp pe,#1234:ex de,hl:call pe,#1234:nop:xor #12:rst #28::ret p:pop af:" \ - "jp p,#1234:di:call p,#1234:push af:or #12:rst #30:ret m:ld sp,hl:jp m,#1234:ei:call m,#1234:nop:" \ - "cp #12:rst #38:in b,(c):out (c),b:sbc hl,bc:ld (#1234),bc:neg:retn:im 0:ld i,a:in c,(c):out (c),c:" \ - "adc hl,bc:ld bc,(#1234):reti:ld r,a::in d,(c):out (c),d:sbc hl,de:ld (#1234),de:retn:im 1:ld a,i:" \ - "in e,(c):out (c),e:adc hl,de:ld de,(#1234):im 2:ld a,r::in h,(c):out (c),h:sbc hl,hl:rrd:in l,(c):" \ - "out (c),l:adc hl,hl:rld::in 0,(c):out (c),0:sbc hl,sp:ld (#1234),sp:in a,(c):out (c),a:adc hl,sp:" \ - "ld sp,(#1234)::ldi:cpi:ini:outi:ldd:cpd:ind:outd::ldir:cpir:inir:otir:lddr:cpdr:indr:otdr::rlc b:" \ - "rlc c:rlc d:rlc e:rlc h:rlc l:rlc (hl):rlc a:rrc b:rrc c:rrc d:rrc e:rrc h:rrc l:rrc (hl):rrc a::" \ - "rl b:rl c:rl d:rl e:rl h:rl l:rl (hl):rl a:rr b:rr c:rr d:rr e:rr h:rr l:rr (hl):rr a:sla b:sla c:" \ - "sla d:sla e:sla h:sla l:sla (hl):sla a:sra b:sra c:sra d:sra e:sra h:sra l:sra (hl):sra a::sll b:" \ - "sll c:sll d:sll e:sll h:sll l:sll (hl):sll a:srl b:srl c:srl d:srl e:srl h:srl l:srl (hl):srl a::" \ - "bit 0,b:bit 0,c:bit 0,d:bit 0,e:bit 0,h:bit 0,l:bit 0,(hl):bit 0,a::bit 1,b:bit 1,c:bit 1,d:bit 1,e:" \ - "bit 1,h:bit 1,l:bit 1,(hl):bit 1,a::bit 2,b:bit 2,c:bit 2,d:bit 2,e:bit 2,h:bit 2,l:bit 2,(hl):" \ - "bit 2,a::bit 3,b:bit 3,c:bit 3,d:bit 3,e:bit 3,h:bit 3,l:bit 3,(hl):bit 3,a::bit 4,b:bit 4,c:" \ - "bit 4,d:bit 4,e:bit 4,h:bit 4,l:bit 4,(hl):bit 4,a::bit 5,b:bit 5,c:bit 5,d:bit 5,e:bit 5,h:bit 5,l:" \ - "bit 5,(hl):bit 5,a::bit 6,b:bit 6,c:bit 6,d:bit 6,e:bit 6,h:bit 6,l:bit 6,(hl):bit 6,a::bit 7,b:" \ - "bit 7,c:bit 7,d:bit 7,e:bit 7,h:bit 7,l:bit 7,(hl):bit 7,a::res 0,b:res 0,c:res 0,d:res 0,e:res 0,h:" \ - "res 0,l:res 0,(hl):res 0,a::res 1,b:res 1,c:res 1,d:res 1,e:res 1,h:res 1,l:res 1,(hl):res 1,a::" \ - "res 2,b:res 2,c:res 2,d:res 2,e:res 2,h:res 2,l:res 2,(hl):res 2,a::res 3,b:res 3,c:res 3,d:res 3,e:" \ - "res 3,h:res 3,l:res 3,(hl):res 3,a::res 4,b:res 4,c:res 4,d:res 4,e:res 4,h:res 4,l:res 4,(hl):" \ - "res 4,a::res 5,b:res 5,c:res 5,d:res 5,e:res 5,h:res 5,l:res 5,(hl):res 5,a::res 6,b:res 6,c:" \ - "res 6,d:res 6,e:res 6,h:res 6,l:res 6,(hl):res 6,a::res 7,b:res 7,c:res 7,d:res 7,e:res 7,h:res 7,l:" \ - "res 7,(hl):res 7,a::set 0,b:set 0,c:set 0,d:set 0,e:set 0,h:set 0,l:set 0,(hl):set 0,a::set 1,b:" \ - "set 1,c:set 1,d:set 1,e:set 1,h:set 1,l:set 1,(hl):set 1,a::set 2,b:set 2,c:set 2,d:set 2,e:set 2,h:" \ - "set 2,l:set 2,(hl):set 2,a::set 3,b:set 3,c:set 3,d:set 3,e:set 3,h:set 3,l:set 3,(hl):set 3,a::" \ - "set 4,b:set 4,c:set 4,d:set 4,e:set 4,h:set 4,l:set 4,(hl):set 4,a::set 5,b:set 5,c:set 5,d:set 5,e:" \ - "set 5,h:set 5,l:set 5,(hl):set 5,a::set 6,b:set 6,c:set 6,d:set 6,e:set 6,h:set 6,l:set 6,(hl):" \ - "set 6,a::set 7,b:set 7,c:set 7,d:set 7,e:set 7,h:set 7,l:set 7,(hl):set 7,a::add ix,bc::add ix,de::" \ - "ld ix,#1234:ld (#1234),ix:inc ix:inc xh:dec xh:ld xh,#12:add ix,ix:ld ix,(#1234):dec ix:inc xl:" \ - "dec xl:ld xl,#12::inc (ix+#12):dec (ix+#12):ld (ix+#12),#34:add ix,sp::ld b,xh:ld b,xl:" \ - "ld b,(ix+#12):ld c,xh:ld c,xl:ld c,(ix+#12):::ld d,xh:ld d,xl:ld d,(ix+#12):ld e,xh:ld e,xl:" \ - "ld e,(ix+#12)::ld xh,b:ld xh,c:ld xh,d:ld xh,e:ld xh,xh:ld xh,xl:ld h,(ix+#12):ld xh,a:ld xl,b:" \ - "ld xl,c:ld xl,d:ld xl,e:ld xl,xh:ld xl,xl:ld l,(ix+#12):ld xl,a::ld (ix+#12),b:ld (ix+#12),c:" \ - "ld (ix+#12),d:ld (ix+#12),e:ld (ix+#12),h:ld (ix+#12),l:ld (ix+#12),a:ld a,xh:ld a,xl:" \ - "ld a,(ix+#12)::add xh:add xl:add (ix+#12):adc xh:adc xl:adc (ix+#12)::sub xh:sub xl:sub (ix+#12):" \ - "sbc xh:sbc xl:sbc (ix+#12)::and xh:and xl:and (ix+#12):xor xh:xor xl:xor (ix+#12)::or xh:or xl:" \ - "or (ix+#12):cp xh:cp xl:cp (ix+#12)::pop ix:ex (sp),ix:push ix:jp (ix)::ld sp,ix:::rlc (ix+#12),b:" \ - "rlc (ix+#12),c:rlc (ix+#12),d:rlc (ix+#12),e:rlc (ix+#12),h:rlc (ix+#12),l:rlc (ix+#12):" \ - "rlc (ix+#12),a:rrc (ix+#12),b:rrc (ix+#12),c:rrc (ix+#12),d:rrc (ix+#12),e:rrc (ix+#12),h:" \ - "rrc (ix+#12),l:rrc (ix+#12):rrc (ix+#12),a::rl (ix+#12),b:rl (ix+#12),c:rl (ix+#12),d:rl (ix+#12),e:" \ - "rl (ix+#12),h:rl (ix+#12),l:rl (ix+#12):rl (ix+#12),a:rr (ix+#12),b:rr (ix+#12),c:rr (ix+#12),d:" \ - "rr (ix+#12),e:rr (ix+#12),h:rr (ix+#12),l:rr (ix+#12):rr (ix+#12),a::sla (ix+#12),b:sla (ix+#12),c:" \ - "sla (ix+#12),d:sla (ix+#12),e:sla (ix+#12),h:sla (ix+#12),l:sla (ix+#12):sla (ix+#12),a:" \ - "sra (ix+#12),b:sra (ix+#12),c:sra (ix+#12),d:sra (ix+#12),e:sra (ix+#12),h:sra (ix+#12),l:" \ - "sra (ix+#12):sra (ix+#12),a::sll (ix+#12),b:sll (ix+#12),c:sll (ix+#12),d:sll (ix+#12),e:" \ - "sll (ix+#12),h:sll (ix+#12),l:sll (ix+#12):sll (ix+#12),a:srl (ix+#12),b:srl (ix+#12),c:" \ - "srl (ix+#12),d:srl (ix+#12),e:srl (ix+#12),h:srl (ix+#12),l:srl (ix+#12):srl (ix+#12),a::" \ - "bit 0,(ix+#12):bit 1,(ix+#12):bit 2,(ix+#12):bit 3,(ix+#12):bit 4,(ix+#12):bit 5,(ix+#12):" \ - "bit 6,(ix+#12):bit 7,(ix+#12):bit 0,(ix+#12),d:bit 1,(ix+#12),b:bit 2,(ix+#12),c:bit 3,(ix+#12),d:" \ - "bit 4,(ix+#12),e:bit 5,(ix+#12),h:bit 6,(ix+#12),l:bit 7,(ix+#12),a:::res 0,(ix+#12),b:" \ - "res 0,(ix+#12),c:res 0,(ix+#12),d:res 0,(ix+#12),e:res 0,(ix+#12),h:res 0,(ix+#12),l:res 0,(ix+#12):" \ - "res 0,(ix+#12),a::res 1,(ix+#12),b:res 1,(ix+#12),c:res 1,(ix+#12),d:res 1,(ix+#12),e:" \ - "res 1,(ix+#12),h:res 1,(ix+#12),l:res 1,(ix+#12):res 1,(ix+#12),a::res 2,(ix+#12),b:" \ - "res 2,(ix+#12),c:res 2,(ix+#12),d:res 2,(ix+#12),e:res 2,(ix+#12),h:res 2,(ix+#12),l:res 2,(ix+#12):" \ - "res 2,(ix+#12),a::res 3,(ix+#12),b:res 3,(ix+#12),c:res 3,(ix+#12),d:res 3,(ix+#12),e:" \ - "res 3,(ix+#12),h:res 3,(ix+#12),l:res 3,(ix+#12):res 3,(ix+#12),a::res 4,(ix+#12),b:" \ - "res 4,(ix+#12),c:res 4,(ix+#12),d:res 4,(ix+#12),e:res 4,(ix+#12),h:res 4,(ix+#12),l:" \ - "res 4,(ix+#12):res 4,(ix+#12),a::res 5,(ix+#12),b:res 5,(ix+#12),c:res 5,(ix+#12),d:" \ - "res 5,(ix+#12),e:res 5,(ix+#12),h:res 5,(ix+#12),l:res 5,(ix+#12):res 5,(ix+#12),a::" \ - "res 6,(ix+#12),b:res 6,(ix+#12),c:res 6,(ix+#12),d:res 6,(ix+#12),e:res 6,(ix+#12),h:" \ - "res 6,(ix+#12),l:res 6,(ix+#12):res 6,(ix+#12),a::res 7,(ix+#12),b:res 7,(ix+#12),c:" \ - "res 7,(ix+#12),d:res 7,(ix+#12),e:res 7,(ix+#12),h:res 7,(ix+#12),l:res 7,(ix+#12):" \ - "res 7,(ix+#12),a::set 0,(ix+#12),b:set 0,(ix+#12),c:set 0,(ix+#12),d:set 0,(ix+#12),e:" \ - "set 0,(ix+#12),h:set 0,(ix+#12),l:set 0,(ix+#12):set 0,(ix+#12),a::set 1,(ix+#12),b:" \ - "set 1,(ix+#12),c:set 1,(ix+#12),d:set 1,(ix+#12),e:set 1,(ix+#12),h:set 1,(ix+#12),l:" \ - "set 1,(ix+#12):set 1,(ix+#12),a::set 2,(ix+#12),b:set 2,(ix+#12),c:set 2,(ix+#12),d:" \ - "set 2,(ix+#12),e:set 2,(ix+#12),h:set 2,(ix+#12),l:set 2,(ix+#12):set 2,(ix+#12),a::" \ - "set 3,(ix+#12),b:set 3,(ix+#12),c:set 3,(ix+#12),d:set 3,(ix+#12),e:set 3,(ix+#12),h:" \ - "set 3,(ix+#12),l:set 3,(ix+#12):set 3,(ix+#12),a::set 4,(ix+#12),b:set 4,(ix+#12),c:" \ - "set 4,(ix+#12),d:set 4,(ix+#12),e:set 4,(ix+#12),h:set 4,(ix+#12),l:set 4,(ix+#12):" \ - "set 4,(ix+#12),a::set 5,(ix+#12),b:set 5,(ix+#12),c:set 5,(ix+#12),d:set 5,(ix+#12),e:" \ - "set 5,(ix+#12),h:set 5,(ix+#12),l:set 5,(ix+#12):set 5,(ix+#12),a::set 6,(ix+#12),b:" \ - "set 6,(ix+#12),c:set 6,(ix+#12),d:set 6,(ix+#12),e:set 6,(ix+#12),h:set 6,(ix+#12),l:" \ - "set 6,(ix+#12):set 6,(ix+#12),a::set 7,(ix+#12),b:set 7,(ix+#12),c:set 7,(ix+#12),d:" \ - "set 7,(ix+#12),e:set 7,(ix+#12),h:set 7,(ix+#12),l:set 7,(ix+#12):set 7,(ix+#12),a::add iy,bc::" \ - "add iy,de::ld iy,#1234:ld (#1234),iy:inc iy:inc yh:dec yh:ld yh,#12:add iy,iy:ld iy,(#1234):dec iy:" \ - "inc yl:dec yl:ld yl,#12::inc (iy+#12):dec (iy+#12):ld (iy+#12),#34:add iy,sp::ld b,yh:ld b,yl:" \ - "ld b,(iy+#12):ld c,yh:ld c,yl:ld c,(iy+#12):::ld d,yh:ld d,yl:ld d,(iy+#12):ld e,yh:ld e,yl:" \ - "ld e,(iy+#12)::ld yh,b:ld yh,c:ld yh,d:ld yh,e:ld yh,yh:ld yh,yl:ld h,(iy+#12):ld yh,a:ld yl,b:" \ - "ld yl,c:ld yl,d:ld yl,e:ld yl,yh:ld yl,yl:ld l,(iy+#12):ld yl,a::ld (iy+#12),b:ld (iy+#12),c:" \ - "ld (iy+#12),d:ld (iy+#12),e:ld (iy+#12),h:ld (iy+#12),l:ld (iy+#12),a:ld a,yh:ld a,yl:" \ - "ld a,(iy+#12)::add yh:add yl:add (iy+#12):adc yh:adc yl:adc (iy+#12)::sub yh:sub yl:" \ - "sub (iy+#12):sbc yh:sbc yl:sbc (iy+#12)::and yh:and yl:and (iy+#12):xor yh:xor yl:xor (iy+#12)::" \ - "or yh:or yl:or (iy+#12):cp yh:cp yl:cp (iy+#12)::pop iy:ex (sp),iy:push iy:jp (iy)::ld sp,iy::" \ - "rlc (iy+#12),b:rlc (iy+#12),c:rlc (iy+#12),d:rlc (iy+#12),e:rlc (iy+#12),h:rlc (iy+#12),l:" \ - "rlc (iy+#12):rlc (iy+#12),a:rrc (iy+#12),b:rrc (iy+#12),c:rrc (iy+#12),d:rrc (iy+#12),e:" \ - "rrc (iy+#12),h:rrc (iy+#12),l:rrc (iy+#12):rrc (iy+#12),a::rl (iy+#12),b:rl (iy+#12),c:" \ - "rl (iy+#12),d:rl (iy+#12),e:rl (iy+#12),h:rl (iy+#12),l:rl (iy+#12):rl (iy+#12),a:rr (iy+#12),b:" \ - "rr (iy+#12),c:rr (iy+#12),d:rr (iy+#12),e:rr (iy+#12),h:rr (iy+#12),l:rr (iy+#12):rr (iy+#12),a::" \ - "sla (iy+#12),b:sla (iy+#12),c:sla (iy+#12),d:sla (iy+#12),e:sla (iy+#12),h:sla (iy+#12),l:" \ - "sla (iy+#12):sla (iy+#12),a:sra (iy+#12),b:sra (iy+#12),c:sra (iy+#12),d:sra (iy+#12),e:" \ - "sra (iy+#12),h:sra (iy+#12),l:sra (iy+#12):sra (iy+#12),a::sll (iy+#12),b:sll (iy+#12),c:" \ - "sll (iy+#12),d:sll (iy+#12),e:sll (iy+#12),h:sll (iy+#12),l:sll (iy+#12):sll (iy+#12),a:" \ - "srl (iy+#12),b:srl (iy+#12),c:srl (iy+#12),d:srl (iy+#12),e:srl (iy+#12),h:srl (iy+#12),l:" \ - "srl (iy+#12):srl (iy+#12),a::bit 0,(iy+#12):bit 1,(iy+#12):bit 2,(iy+#12):bit 3,(iy+#12):" \ - "bit 4,(iy+#12):bit 5,(iy+#12):bit 6,(iy+#12):bit 7,(iy+#12)::res 0,(iy+#12),b:res 0,(iy+#12),c:" \ - "res 0,(iy+#12),d:res 0,(iy+#12),e:res 0,(iy+#12),h:res 0,(iy+#12),l:res 0,(iy+#12):" \ - "res 0,(iy+#12),a::res 1,(iy+#12),b:res 1,(iy+#12),c:res 1,(iy+#12),d:res 1,(iy+#12),e:" \ - "res 1,(iy+#12),h:res 1,(iy+#12),l:res 1,(iy+#12):res 1,(iy+#12),a::res 2,(iy+#12),b:" \ - "res 2,(iy+#12),c:res 2,(iy+#12),d:res 2,(iy+#12),e:res 2,(iy+#12),h:res 2,(iy+#12),l:" \ - "res 2,(iy+#12):res 2,(iy+#12),a::res 3,(iy+#12),b:res 3,(iy+#12),c:res 3,(iy+#12),d:" \ - "res 3,(iy+#12),e:res 3,(iy+#12),h:res 3,(iy+#12),l:res 3,(iy+#12):res 3,(iy+#12),a::" \ - "res 4,(iy+#12),b:res 4,(iy+#12),c:res 4,(iy+#12),d:res 4,(iy+#12),e:res 4,(iy+#12),h:" \ - "res 4,(iy+#12),l:res 4,(iy+#12):res 4,(iy+#12),a::res 5,(iy+#12),b:res 5,(iy+#12),c:" \ - "res 5,(iy+#12),d:res 5,(iy+#12),e:res 5,(iy+#12),h:res 5,(iy+#12),l:res 5,(iy+#12):" \ - "res 5,(iy+#12),a::res 6,(iy+#12),b:res 6,(iy+#12),c:res 6,(iy+#12),d:res 6,(iy+#12),e:" \ - "res 6,(iy+#12),h:res 6,(iy+#12),l:res 6,(iy+#12):res 6,(iy+#12),a::res 7,(iy+#12),b:" \ - "res 7,(iy+#12),c:res 7,(iy+#12),d:res 7,(iy+#12),e:res 7,(iy+#12),h:res 7,(iy+#12),l:" \ - "res 7,(iy+#12):res 7,(iy+#12),a::set 0,(iy+#12),b:set 0,(iy+#12),c:set 0,(iy+#12),d:" \ - "set 0,(iy+#12),e:set 0,(iy+#12),h:set 0,(iy+#12),l:set 0,(iy+#12):set 0,(iy+#12),a::" \ - "set 1,(iy+#12),b:set 1,(iy+#12),c:set 1,(iy+#12),d:set 1,(iy+#12),e:set 1,(iy+#12),h:" \ - "set 1,(iy+#12),l:set 1,(iy+#12):set 1,(iy+#12),a::set 2,(iy+#12),b:set 2,(iy+#12),c:" \ - "set 2,(iy+#12),d:set 2,(iy+#12),e:set 2,(iy+#12),h:set 2,(iy+#12),l:set 2,(iy+#12):" \ - "set 2,(iy+#12),a::set 3,(iy+#12),b:set 3,(iy+#12),c:set 3,(iy+#12),d:set 3,(iy+#12),e:" \ - "set 3,(iy+#12),h:set 3,(iy+#12),l:set 3,(iy+#12):set 3,(iy+#12),a::set 4,(iy+#12),b:" \ - "set 4,(iy+#12),c:set 4,(iy+#12),d:set 4,(iy+#12),e:set 4,(iy+#12),h:set 4,(iy+#12),l:" \ - "set 4,(iy+#12):set 4,(iy+#12),a::set 5,(iy+#12),b:set 5,(iy+#12),c:set 5,(iy+#12),d:" \ - "set 5,(iy+#12),e:set 5,(iy+#12),h:set 5,(iy+#12),l:set 5,(iy+#12):set 5,(iy+#12),a::" \ - "set 6,(iy+#12),b:set 6,(iy+#12),c:set 6,(iy+#12),d:set 6,(iy+#12),e:set 6,(iy+#12),h:" \ - "set 6,(iy+#12),l:set 6,(iy+#12):set 6,(iy+#12),a::set 7,(iy+#12),b:set 7,(iy+#12),c:" \ - "set 7,(iy+#12),d:set 7,(iy+#12),e:set 7,(iy+#12),h:set 7,(iy+#12),l:set 7,(iy+#12):" \ - "set 7,(iy+#12),a:" - -#define AUTOTEST_LABNUM "mavar=67:label{mavar}truc:ld hl,7+2*label{mavar}truc:mnt=1234567:lab2{mavar}{mnt}:" \ - "ld de,lab2{mavar}{mnt}:lab3{mavar}{mnt}h:ld de,lab3{mavar}{mnt}h" - -#define AUTOTEST_EQUNUM "mavar = 9:monlabel{mavar+5}truc:unalias{mavar+5}heu equ 50:autrelabel{unalias14heu}:ld hl,autrelabel50" - -#define AUTOTEST_DELAYNUM "macro test label: dw {label}: endm: repeat 3, idx:idx2 = idx-1:" \ - " test label_{idx2}: rend:repeat 3, idx:label_{idx-1}:nop:rend" - -#define AUTOTEST_STRUCT "org #1000:label1 :struct male:age defb 0:height defb 0:endstruct:struct female:" \ - "age defb 0:height defb 0:endstruct:struct couple:struct male husband:" \ - "struct female wife:endstruct:if $-label1!=0:stop:endif:ld a,(ix+couple.wife.age):" \ - "ld bc,couple:ld bc,{sizeof}couple:struct couple mycouple:" \ - "if mycouple.husband != mycouple.husband.age:stop:endif:ld hl,mycouple:" \ - "ld hl,mycouple.wife.age:ld bc,{sizeof}mycouple:macro cmplastheight p1:" \ - "ld hl,@mymale.height:ld a,{p1}:cp (hl):ld bc,{sizeof}@mymale:ld hl,@mymale:ret:" \ - "struct male @mymale:mend:cmplastheight 5:cmplastheight 3:nop" - -#define AUTOTEST_STRUCT2 "struct bite: preums defb 0: deuze defw 1: troize defs 10: endstruct:" \ - " if {sizeof}bite.preums!=1 || {sizeof}bite.deuze!=2 || {sizeof}bite.troize!=10: stop: endif: nop " - -#define AUTOTEST_REPEAT "ce=100:repeat 2,ce:repeat 5,cx:repeat 5,cy:defb cx*cy:rend:rend:rend:assert cx==6 && cy==6 && ce==3:" \ - "cpt=0:repeat:cpt=cpt+1:until cpt>4:assert cpt==5" - -#define AUTOTEST_REPEATKO "repeat 5:nop" - -#define AUTOTEST_WHILEKO "while 5:nop" - -#define AUTOTEST_TICKER "repeat 2: ticker start, mc:out (0),a:out (c),a:out (c),h:out (c),0:ticker stop, mc:if mc!=15:ld hl,bite:else:nop:endif:rend" - -#define AUTOTEST_ORG "ORG #8000,#1000:defw $:ORG $:defw $" - -#define AUTOTEST_BANKORG "bank 0:nop:org #5:nop:bank 1:unevar=10:bank 0:assert $==6:ret:bank 1:assert $==0:bank 0:assert $==7" - -#define AUTOTEST_VAREQU "label1 equ #C000:label2 equ (label1*2)/16:label3 equ label1-label2:label4 equ 15:var1=50*3+2:var2=12*label1:var3=label4-8:var4=label2:nop" - -#define AUTOTEST_FORMAT "hexa=#12A+$23B+45Ch+0x56D:deci=123.45+-78.54*2-(7-7)*2:bina=0b101010+1010b-%1111:assert hexa==3374 && deci==-33.63 && bina==37:nop" - -#define AUTOTEST_CHARSET "charset 'abcde',0:defb 'abcde':defb 'a','b','c','d','e':defb 'a',1*'b','c'*1,1*'d','e'*1:charset:" \ - "defb 'abcde':defb 'a','b','c','d','e':defb 'a',1*'b','c'*1,1*'d','e'*1" - -#define AUTOTEST_CHARSET2 "charset 97,97+26,0:defb 'roua':charset:charset 97,10:defb 'roua':charset 'o',5:defb 'roua':charset 'ou',6:defb 'roua'" - -#define AUTOTEST_NOCODE "let monorg=$:NoCode:Org 0:Element1 db 0:Element2 dw 3:Element3 ds 50:Element4 defb 'rdd':Org 0:pouet defb 'nop':" \ - "Code:Org monorg:cpt=$+element2+element3+element4:defs cpt,0" - -#define AUTOTEST_LZSEGMENT "org #100:debut:jr nz,zend:lz48:repeat 128:nop:rend:lzclose:jp zend:lz48:repeat 2:dec a:jr nz,@next:ld a,5:@next:jp debut:rend:" \ - "lzclose:zend" - -#define AUTOTEST_PAGETAG "bankset 0:org #5000:label1:bankset 1:org #9000:label2:bankset 2:" \ - "assert {page}label1==0x7FC0:assert {page}label2==0x7FC6:assert {pageset}label1==#7FC0:assert {pageset}label2==#7FC2:nop" - -#define AUTOTEST_PAGETAG2 "bankset 0:call maroutine:bank 4:org #C000:autreroutine:nop:" \ - "ret:bank 5:org #8000:maroutine:ldir:ret:bankset 2:org #9000:troize:nop:" \ - "assert {page}maroutine==#7FC5:assert {pageset}maroutine==#7FC2:assert {page}autreroutine==#7FC4:" \ - "assert {pageset}autreroutine==#7FC2:assert {page}troize==#7FCE:assert {pageset}troize==#7FCA" - -#define AUTOTEST_PAGETAG3 "buildsna:bank 2:assert {bank}$==2:assert {page}$==0x7FC0:assert {pageset}$==#7FC0:" \ - "bankset 1:org #4000:assert {bank}$==5:assert {page}$==0x7FC5:assert {pageset}$==#7FC2" - -#define AUTOTEST_SWITCH "mavar=4:switch mavar:case 1:nop:case 4:defb 4:case 3:defb 3:break:case 2:nop:case 4:defb 4:endswitch" - -#define AUTOTEST_PREPRO0 "\n\n\n\n;bitch\n\nnop\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nxor a\n\n\n\n\n\n\n\n\n\n\n\n" - -#define AUTOTEST_PREPRO1 " macro DEBUG_INK0, coul: out (c), a: endm: ifndef NDEBUG:DEBUG_BORDER_NOPS = 0: endif" - -#define AUTOTEST_PREPRO2 " nop : mycode other tartine ldir : defw tartine,other, mycode : assert tartine==other && other==mycode && mycode==1 && $==9" - -#define AUTOTEST_PREPRO3 "nop\n \n /* test ' ici */\n nop /* retest */ 5\n /* bonjour\n prout\n caca\n pipi */" \ - " nop\n nop /* nop */ : nop\n ; grouik /*\n \n /* ; pouet */ ld hl,#2121\n " - -#define AUTOTEST_PREPRO4 "glop=0\n nop ; glop=1\n assert glop==0\n nop\n glop=0\n nop // glop=1\n assert glop==0\n nop\n glop=0 : /* glop=1 */ nop\n" \ - "assert glop==0\n nop\n \n glop=0 : /* glop=1 // */ nop\n assert glop==0\n nop\n glop=0 : /* glop=1 ; */ nop\n" \ - "assert glop==0\n nop\n glop=0 ; /* glop=1\n nop // glop=2 /*\n assert glop==0\n nop\n" - -#define AUTOTEST_PROXIM "routine:.step1:jp .step2:.step2:jp .step1:deuze:nop:.step1:djnzn .step1:djnz routine.step2" - -#define AUTOTEST_TAGPRINT "unevar=12:print 'trucmuche{unevar}':print '{unevar}':print '{unevar}encore','pouet{unevar}{unevar}':ret" - -#define AUTOTEST_TAGFOLLOW "ret:uv=1234567890:unlabel_commeca_{uv} equ pouetpouetpouettroulala:pouetpouetpouettroulala:assert unlabel_commeca_{uv}>0" - -#define AUTOTEST_TAGREALLOC "zoomscroller_scroller_height equ 10: another_super_long_equ equ 256: pinouille_super_long_useless_equ equ 0: " \ - "zz equ 1111111111: org #100: repeat zoomscroller_scroller_height,idx: " \ - "zoomscroller_buffer_line_{idx-1}_{pinouille_super_long_useless_equ} nop: zoomscroller_buffer_line_{idx-1}_{zz} nop: " \ - "rend: align 256: repeat zoomscroller_scroller_height,idx: zoomscroller_buffer_line_{idx-1}_{pinouille_super_long_useless_equ}_duplicate nop: " \ - "zoomscroller_buffer_line_{idx-1}_{zz}_duplicate nop: rend: repeat zoomscroller_scroller_height, line: idx = line - 1: " \ - "assert zoomscroller_buffer_line_{idx}_{pinouille_super_long_useless_equ} + another_super_long_equ == "\ - "zoomscroller_buffer_line_{idx}_{pinouille_super_long_useless_equ}_duplicate: " \ - "assert zoomscroller_buffer_line_{idx}_{zz} + another_super_long_equ == zoomscroller_buffer_line_{idx}_{zz}_duplicate: rend" - -#define AUTOTEST_DEFUSED "ld hl,labelused :ifdef labelused:fail 'labelexiste':endif:ifndef labelused:else:fail 'labelexiste':endif:" \ - "ifnused labelused:fail 'labelused':endif:ifused labelused:else:fail 'labelused':endif:labelused" - -#define AUTOTEST_SAVEINVALID1 "nop : save'gruik',20,-100" - -#define AUTOTEST_SAVEINVALID2 "nop : save'gruik',-20,100" - -#define AUTOTEST_SAVEINVALID3 "nop : save'gruik',40000,30000" - -#define AUTOTEST_MACROPROX " macro unemacro: nop: endm: global_label: ld hl, .table: .table" - -#define AUTOTEST_PROXBACK " macro grouik: @truc djnz @truc: .unprox djnz .unprox: mend:" \ - "ld b,2: unglobal nop: djnz unglobal: ld b,2: .unprox nop: djnz .unprox: beforelocal=$ :" \ - "repeat 2: @unlocal: ld b,2: .unprox nop: djnz .unprox: grouik : djnz .unprox : rend: assert .unprox < beforelocal : nop" -#define AUTOTEST_LOCAPROX "repeat 1: @label nop: .prox nop: @label2 nop: djnz @label.prox: rend" - -#define AUTOTEST_QUOTES "defb 'rdd':str 'rdd':charset 'rd',0:defb '\\r\\d':str '\\r\\d'" - -#define AUTOTEST_NEGATIVE "ld a,-5: ld bc,-0x3918:ld de,0+-#3918:ld de,-#3918:var1=-5+6:var2=-#3918+#3919:assert var1+var2==2" - -#define AUTOTEST_FORMULA1 "a=5:b=2:assert int(a/b)==3:assert !a+!b==0:a=a*100:b=b*100:assert a*b==100000:ld hl,a*b-65536:a=123+-5*(-6/2)-50*2<<1" - -#define AUTOTEST_FORMULA2 "vala= (0.5+(4*0.5))*6:valb= int((0.5+(4*0.5))*6):nop:if vala!=valb:push erreur:endif" - -#define AUTOTEST_SHIFTMAX "a=45: a=a>>256: assert a==0:nop" - -#define AUTOTEST_FRAC "mavar=frac(5.5):assert mavar==0.5:assert frac(6.6)==0.6:assert frac(1.1)==0.1:assert frac(1)==0:assert frac(100000)==0:nop" - -/* test override control between bank and bankset in snapshot mode + temp workspace */ -#define AUTOTEST_BANKSET "buildsna:bank 0:nop:bank 1:nop:bank:nop:bank 2:nop:bank 3:nop:bankset 1:nop:bank 8:nop:bank 9:nop:bank 10:nop:bank 11:nop" - -#define AUTOTEST_LIMITOK "org #100:limit #102:nop:limit #103:ld a,0:protect #105,#107:limit #108:xor a:org $+3:inc a" - -#define AUTOTEST_LIMITKO "limit #100:org #100:add ix,ix" - -#define AUTOTEST_DEFS "defs 256,0" - -#define AUTOTEST_LIMIT03 "limit -1 : nop" -#define AUTOTEST_LIMIT04 "limit #10000 : nop" -#define AUTOTEST_LIMIT05 "org #FFFF : ldir" -#define AUTOTEST_LIMIT06 "org #FFFF : nop" - -#define AUTOTEST_LIMIT07 "org #ffff : Start: equ $ : di : ld hl,#c9fb : ld (#38),hl" - -#define AUTOTEST_DELAYED_RUN "run _start:nop:_start nop" - -#define AUTOTEST_INHIBITION "if 0:ifused truc:ifnused glop:ifdef bidule:ifndef machin:ifnot 1:nop:endif:nop:else:nop:endif:endif:endif:endif:endif" - -#define AUTOTEST_LZ4 "lz4:repeat 10:nop:rend:defb 'roudoudoudouoneatxkjhgfdskljhsdfglkhnopnopnopnop':lzclose" - -#define AUTOTEST_MAXERROR "repeat 20:aglapi:rend:nop" - -#define AUTOTEST_ENHANCED_LD "ld h,(ix+11): ld l,(ix+10): ld h,(iy+21): ld l,(iy+20): ld b,(ix+11): ld c,(ix+10):" \ - "ld b,(iy+21): ld c,(iy+20): ld d,(ix+11): ld e,(ix+10): ld d,(iy+21): ld e,(iy+20): ld hl,(ix+10): " \ - "ld hl,(iy+20):ld bc,(ix+10):ld bc,(iy+20): ld de,(ix+10):ld de,(iy+20)" - -#define AUTOTEST_ENHANCED_PUSHPOP "push bc,de,hl,ix,iy,af:pop hl,bc,de,iy,ix,af:nop 2:" \ - "push bc:push de:push hl:push ix:push iy:push af:"\ - "pop hl:pop bc:pop de:pop iy:pop ix:pop af:nop:nop" -#define AUTOTEST_ENHANCED_LD2 "ld (ix+0),hl: ld (ix+0),de: ld (ix+0),bc: ld (iy+0),hl: ld (iy+0),de: ld (iy+0),bc:"\ -"ld (ix+1),h: ld (ix+0),l: ld (ix+1),d: ld (ix+0),e: ld (ix+1),b: ld (ix+0),c: ld (iy+1),h: ld (iy+0),l: ld (iy+1),d: ld (iy+0),e: ld (iy+1),b: ld (iy+0),c" - -#define AUTOTEST_INHIBITION2 "ifdef roudoudou:macro glop bank,page,param:ld a,{bank}:ld hl,{param}{bank}:if {bank}:nop:else:exx:" \ - "endif::switch {param}:nop:case 4:nop:case {param}:nop:default:nop:break:endswitch:endif:defb 'coucou'" - -#define AUTOTEST_INHIBITIONMAX "roudoudou:ifndef roudoudou:if pouet:macro glop bank,page,param:ifdef nanamouskouri:ld hl,{param}{bank}:"\ - "elseif aglapi:exx:endif:if {bank}:nop:elseif {grouik}:exx:endif:switch {bite}:nop:case {nichon}:nop:default:nop:break:endswitch:else:"\ - "ifnot {jojo}:exx:endif:endif:else:defb 'coucou':endif" - -#define AUTOTEST_NOEXPORT "unlabel nop:.unlocal nop:unevar=5:unequ equ 10:noexport unlabel, .unlocal, "\ - "unlabel.unlocal, unevar, unequ:enoexport unlabel, .unlocal, unlabel.unlocal, unevar, unequ" - -#define AUTOTEST_UNDERVAR "coucou nop:_coucou nop:_mavar=5:jr _coucou+_mavar:print _mavar" - -#define AUTOTEST_CODESKIP "org #100: nop: old_dollar=$: nocode: defs 10: assert $==old_dollar+10: code: "\ - "assert $==old_dollar+10: org #200: nop: old_dollar=$: nocode: defs 10: assert $==old_dollar+10: code skip: assert $==old_dollar" - -#define AUTOTEST_EMBEDDED_ERRORS "nop : rien : rien : rien : glop nop : glapi nop" - -#define AUTOTEST_EMBEDDED_LABELS " disarkCounter = 0:MACRO dkps:PLY_AKG_DisarkPointerRegionStart_{disarkCounter}:ENDM" \ - ":MACRO dkpe\nPLY_AKG_DisarkPointerRegionEnd_{disarkCounter}:\ndisarkCounter = disarkCounter + 1:ENDM:\ndkps\ndkpe\ndkps" - -#define AUTOTEST_TAGLOOP "tab1 = #100:tab2 = #200:tab3 = #300:macro genreg channel,psg:label{channel} EQU tab{psg} + channeloffset:"\ - "endm:channel=1:while channel <= 9:psg=floor(((channel-1)/3)+1):channeloffset=((channel-1) % 3)*2:"\ - "genreg {channel},{psg}:channel=channel+1:wend:assert LABEL5==#0202:assert LABEL6==#0204:assert LABEL7==#0300:"\ - "assert LABEL8==#0302:nop" - -#define AUTOTEST_PLUSCOLOR " myval=0x123 : assert getr(myval)==2 : assert getb(myval)==3 : assert getg(myval)==1 : assert getv(myval)==1" \ - " : assert setr(2)+setv(1)+setb(3)==0x123 : assert setv(-2)==setv(0) && setb(220)==setb(15) : nop " - -#define AUTOTEST_ASSERT " macro zem,nom,adr: overflow equ $-{adr}: assert $<{adr},{nom}: nop: mend: zem 'bidule',#2FFF :" \ - " macro zem2,nom,adr: overflow2 equ $-{adr}: assert $<{adr},{nom},{adr},overflow2: nop: mend: zem2 'bidule',#2FFF :" \ - " macro zem3,nom,adr: overflow3 equ $-{adr}: assert $<{adr},{nom},{hex}{adr},overflow3: nop: mend: zem3 'bidule',#2FFF " - -#define AUTOTEST_OPERATORASSIGN "a=5 : a*=3 : assert a==15 : a/=5 : assert a==3 : a&=2 : assert a==2 : a+=10 : assert a==12 : "\ - "a-=3 : assert a==9 : a%=5 : assert a==4 : a|=1 : assert a==5 : a<<=3 : assert a==40 : "\ - "a>>=1 : assert a==20 : nop" -#define AUTOTEST_OPERATORASSIGN2 "a=1 : a+=2 : assert a==3 : repeat 2 : a+=10 : rend : assert a==23: a=1 : a-=2 : assert a==-1 : repeat 2 : a-=10 : rend : assert a==-21: " \ - "a=3 : a*=2 : assert a==6 : repeat 2 : a*=10 : rend : assert a==600: a=600 : a/=2 : assert a==300 : repeat 2 : a/=10 : rend : assert a==3 : nop" - - - -struct s_autotest_keyword { - char *keywordtest; - int result; -}; - -struct s_autotest_keyword autotest_keyword[]={ - {"ld ly,h",1}, {"ld lx,h",1}, {"ld ly,l",1}, {"ld lx,l",1}, {"ld hy,h",1}, {"ld hx,h",1}, {"ld hy,l",1}, {"ld hx,l",1}, - {"nop",0},{"nop 2",0},{"nop a",1},{"nop (hl)",1},{"nop nop",1},{"nop grouik",1}, - {"ldir",0},{"ldir 5",1},{"ldir ldir",1},{"ldir (hl)",1},{"ldir a",1},{"ldir grouik",1}, - {"ldi",0},{"ldi 5",1},{"ldi ldi",1},{"ldi (hl)",1},{"ldi a",1},{"ldi grouik",1}, - {"lddr",0},{"lddr 5",1},{"lddr lddr",1},{"lddr (hl)",1},{"lddr a",1},{"lddr groudk",1}, - {"ldd",0},{"ldd 5",1},{"ldd ldd",1},{"ldd (hl)",1},{"ldd a",1},{"ldd groudk",1}, - {"jr $",0},{"jr 0",0},{"jr jr",1},{"jr (hl)",1},{"jr a",1}, - {"jr c,$",0},{"jr c,0",0},{"jr c,jr",1},{"jr c,(hl)",1},{"jr c,a",1}, - {"jr nc,$",0},{"jr nc,0",0},{"jr nc,jr",1},{"jr nc,(hl)",1},{"jr nc,a",1}, - {"jr z,$",0},{"jr 0",0},{"jr jr",1},{"jr (hl)",1},{"jr a",1}, - {"jr nz,$",0},{"jr 0",0},{"jr jr",1},{"jr (hl)",1},{"jr a",1}, - {"jp $",0},{"jp 0",0},{"jp jp",1},{"jp (hl)",0},{"jp (ix)",0},{"jp (iy)",0},{"jp (de)",1},{"jp a",1}, - {"jp c,$",0},{"jp c,0",0},{"jp c,jp",1}, {"jp c,(hl)",1}, {"jp c,(ix)",1}, {"jp c,(iy)",1},{"jp c,(de)",1},{"jp c,a",1}, - {"jp nc,$",0},{"jp nc,0",0},{"jp nc,jp",1},{"jp nc,(hl)",1},{"jp nc,(ix)",1},{"jp nc,(iy)",1},{"jp nc,(de)",1},{"jp nc,a",1}, - {"jp z,$",0},{"jp z,0",0},{"jp z,jp",1}, {"jp z,(hl)",1}, {"jp z,(ix)",1}, {"jp z,(iy)",1},{"jp z,(de)",1},{"jp z,a",1}, - {"jp nz,$",0},{"jp nz,0",0},{"jp nz,jp",1},{"jp nz,(hl)",1},{"jp nz,(ix)",1},{"jp nz,(iy)",1},{"jp nz,(de)",1},{"jp nz,a",1}, - {"jp pe,$",0},{"jp pe,0",0},{"jp pe,jp",1},{"jp pe,(hl)",1},{"jp pe,(ix)",1},{"jp pe,(iy)",1},{"jp pe,(de)",1},{"jp pe,a",1}, - {"jp po,$",0},{"jp po,0",0},{"jp po,jp",1},{"jp po,(hl)",1},{"jp po,(ix)",1},{"jp po,(iy)",1},{"jp po,(de)",1},{"jp po,a",1}, - {"jp p,$",0},{"jp p,0",0},{"jp p,jp",1}, {"jp p,(hl)",1}, {"jp p,(ix)",1}, {"jp p,(iy)",1},{"jp p,(de)",1},{"jp p,a",1}, - {"jp m,$",0},{"jp m,0",0},{"jp m,jp",1}, {"jp m,(hl)",1}, {"jp m,(ix)",1}, {"jp m,(iy)",1},{"jp m,(de)",1},{"jp m,a",1}, - {"ret",0},{"ret c",0},{"ret nc",0},{"ret pe",0},{"ret po",0},{"ret m",0},{"ret p",0},{"reti",0},{"ret ret",1},{"ret 5",1},{"ret (hl)",1},{"ret a",1}, - {"xor a",0},{"xor a,b",1},{"xor",1},{"xor (de)",1},{"xor (hl)",0},{"xor (bc)",1},{"xor (ix+0)",0},{"xor (iy+0)",},{"xor xor",1}, - {"and a",0},{"and a,b",1},{"xor",1},{"and (de)",1},{"and (hl)",0},{"and (bc)",1},{"and (ix+0)",0},{"and (iy+0)",},{"and xor",1}, - {"or a",0},{"or a,b",1},{"xor",1},{"or (de)",1},{"or (hl)",0},{"or (bc)",1},{"or (ix+0)",0},{"or (iy+0)",},{"or xor",1}, - {"add",1},{"add a",0},{"add a,a",0},{"add add",1},{"add (hl)",0},{"add (de)",1},{"add xh",0},{"add grouik",1}, - {"add hl,ix",1},{"add hl,iy",1},{"add ix,iy",1},{"add iy,ix",1},{"add hl,0",1},{"add hl,grouik",1},{"add ix,hl",1},{"add iy,hl",1}, - {"adc",1},{"adc a",0},{"adc a,a",0},{"adc adc",1},{"adc (hl)",0},{"adc (de)",1},{"adc xh",0},{"adc grouik",1}, - {"adc hl,ix",1},{"adc hl,iy",1},{"adc ix,iy",1},{"adc iy,ix",1},{"adc hl,0",1},{"adc hl,grouik",1},{"adc ix,hl",1},{"adc iy,hl",1}, - {"sub",1},{"sub a",0},{"sub a,a",0},{"sub sub",1},{"sub (hl)",0},{"sub (de)",1},{"sub xh",0},{"sub grouik",1}, - {"sub hl,ix",1},{"sub hl,iy",1},{"sub ix,iy",1},{"sub iy,ix",1},{"sub hl,0",1},{"sub hl,grouik",1},{"sub ix,hl",1},{"sub iy,hl",1}, - {"sbc",1},{"sbc a",0},{"sbc a,a",0},{"sbc sbc",1},{"sbc (hl)",0},{"sbc (de)",1},{"sbc xh",0},{"sbc grouik",1}, - {"sbc hl,ix",1},{"sbc hl,iy",1},{"sbc ix,iy",1},{"sbc iy,ix",1},{"sbc hl,0",1},{"sbc hl,grouik",1},{"sbc ix,hl",1},{"sbc iy,hl",1}, - {"exx",0},{"exx hl",1},{"exx hl,de",1},{"exx af,af'",1},{"exx exx",1},{"exx 5",1}, - {"ex",1},{"ex af,af'",0},{"ex hl,de",0},{"ex hl,bc",1},{"ex hl,hl",1},{"ex hl,ix",1}, - {"cp",1},{"cp cp ",1},{"cp 5",0},{"cp c",0},{"cp a,5",0},{"cp a,c",0},{"cp hl",1},{"cp (hl)",0},{"cp a,(hl)",0},{"cp (de)",1},{"cp de",1}, - {"cpi",0},{"cpi (hl)",1},{"cpi a",1},{"cpi 5",1}, - {"cpd",0},{"cpd (hl)",1},{"cpd a",1},{"cpd 5",1}, - {"cpir",0},{"cpir (hl)",1},{"cpir a",1},{"cpir 5",1}, - {"cpdr",0},{"cpdr (hl)",1},{"cpdr a",1},{"cpdr 5",1}, - {"call #1234",0},{"call call",1},{"call (hl)",1},{"call (ix)",1},{"call (iy)",1},{"call (de)",1},{"call hl",1},{"call bc",1},{"call a",1},{"call 5,5",1}, - {"rst 5",1},{"rst",1},{"rst 0",0},{"rst rst",1},{"rst (hl)",1},{"rst (ix)",1},{"rst (iy)",1},{"rst z",1},{"rst z,0",1}, - {"djnz",1},{"djnz $",0},{"djnz $,0",1},{"djnz djnz",1},{"djnz (hl)",1}, - {"djnz (ix)",1},{"djnz (iy)",1},{"djnz (bc)",1},{"djnz bc",1},{"djnz ix",1},{"djnz iy",1},{"djnz hl",1}, - {"push",1},{"push push",1},{"push pop",1},{"push af'",1},{"push (ix)",1},{"push (hl)",1},{"push (#1234)",1},{"push #1234",1}, - {"pop",1},{"pop pop",1},{"pop push",1},{"pop af'",1},{"pop (ix)",1},{"pop (hl)",1},{"pop (#1234)",1},{"pop #1234",1}, - {"set -1,a",1},{"set 9,a",1},{"set 0,xh",1},{"set 0,ix",1},{"set 0",1},{"set",1},{"set set",1},{"set 0,a,a",1},{"set 0,(ix+0),xh",1}, - {"bit -1,a",1},{"bit 9,a",1},{"bit 0,xh",1},{"bit 0,ix",1},{"bit 0",1},{"bit",1},{"bit bit",1},{"bit 0,a,a",1},{"bit 0,(ix+0),xh",1}, - {"res -1,a",1},{"res 9,a",1},{"res 0,xh",1},{"res 0,ix",1},{"res 0",1},{"res",1},{"res res",1},{"res 0,a,a",1},{"res 0,(ix+0),xh",1}, - {"srl",1},{"srl srl",1},{"srl hl",0}, /* srl hl is a kind of macro */ - {"rld a",1},{"rld (hl)",1},{"rld rld",1},{"rld 5",1},{"rld (ix)",1}, - {"rrd a",1},{"rrd (hl)",1},{"rrd rrd",1},{"rrd 5",1},{"rrd (ix)",1}, - {"cpl a",1},{"cpl (hl)",1},{"cpl cpl",1},{"cpl 0",1}, - {"daa daa daa",1},{"daa 0",1},{"daa (hl)",1}, - {"scf scf",1},{"scf 0",1},{"scf (hl)",1}, - {"ccf ccf",1},{"ccf 0",1},{"ccf (hl)",1}, - {"out",1},{"out out",1},{"out (c)",1},{"out (c),xh",1},{"out 0",1}, - {"out (c),hl",1},{"out (hl),c",1},{"out (c),(ix+0)",1},{"out (c),a,b",1}, - {"outi 0",1},{"outi (hl)",1}, - {"otir 0",1},{"otir (hl)",1}, - {"otdr 0",1},{"otdr (hl)",1}, - {"outd 0",1},{"outd (hl)",1}, - {"in",1},{"in in",1},{"in (c)",1},{"in xh,(c)",1},{"in 0",1}, - {"in hl,(c)",1},{"in c,(hl)",1},{"in (c),(ix+0)",1},{"in a,(c),b",1}, - {"ini 0",1},{"ini (hl)",1}, - {"inir 0",1},{"inir (hl)",1}, - {"indr 0",1},{"indr (hl)",1}, - {"ind 0",1},{"ind (hl)",1}, - {"di 5",1},{"di di",1},{"di hl",1},{"di a",1}, - {"ei 5",1},{"ei ei",1},{"ei hl",1},{"ei a",1}, - {"im",1},{"im 3",1},{"im -1",1},{"im (hl)",1}, - {"halt 5",1},{"reti 5",1},{"retn 5",1},{"ld i,b",1},{"ld b,i",1}, - - {"repeat 5:nop:rend",0},{"repeat 100000:a=5:rend",1},{"repeat -5:nop:rend",1},{"repeat repeat:nop:rend",1}, - {"macro bidule:nop:mend:bidule",0},{"macro bidule:nop:macro glop:nop:mend:mend:bidule",1}, - {"macro bidule:nop",1},{"macro bidule:nop:mend:macro glop:nop:bidule",1}, - /* - {"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",}, - {"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",}, - {"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",}, - */ - {NULL,0} -}; - -void MiniDump(unsigned char *opcode, int opcodelen) { - #undef FUNC - #define FUNC "MiniDump" - - int i; - printf("%d byte%s to dump\n",opcodelen,opcodelen>1?"s":""); - for (i=0;i [%s]\n",cpt,tmpsplit[i]);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL; - } - - MemFree(tmpstr3);FreeFields(tmpsplit); - cpt++; -printf("testing various opcode tests OK\n"); - - idx=0; - while (autotest_keyword[idx].keywordtest) { - ret=RasmAssemble(autotest_keyword[idx].keywordtest,strlen(autotest_keyword[idx].keywordtest),&opcode,&opcodelen); - if (!ret && !autotest_keyword[idx].result) { - } else if (ret && autotest_keyword[idx].result) { - } else { - printf("Autotest %03d ERROR ([%s] test) is %s instead of %s\n",cpt,autotest_keyword[idx].keywordtest,!ret?"ok":"ko",ret?"ok":"ko"); - } - if (opcode) MemFree(opcode);opcode=NULL; - idx++; - } - cpt++; -printf("testing moar various opcode tests OK\n"); - - ret=RasmAssemble(AUTOTEST_ORG,strlen(AUTOTEST_ORG),&opcode,&opcodelen); - if (!ret && opcodelen==4 && opcode[1]==0x80 && opcode[2]==2 && opcode[3]==0x10) {} else {printf("Autotest %03d ERROR (ORG relocation)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing ORG relocation OK\n"); - - ret=RasmAssemble(AUTOTEST_MAXERROR,strlen(AUTOTEST_MAXERROR),&opcode,&opcodelen); - if (ret) {} else {printf("Autotest %03d ERROR (must return an error code!)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing error code OK\n"); - - ret=RasmAssemble(AUTOTEST_BANKORG,strlen(AUTOTEST_BANKORG),&opcode,&opcodelen); - if (!ret) {} else {printf("Autotest %03d ERROR (BANK org adr)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing BANK/ORG OK\n"); - - ret=RasmAssemble(AUTOTEST_LIMITOK,strlen(AUTOTEST_LIMITOK),&opcode,&opcodelen); - if (!ret) {} else {printf("Autotest %03d ERROR (limit ok)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing LIMIT 1 OK\n"); - - ret=RasmAssemble(AUTOTEST_LIMITKO,strlen(AUTOTEST_LIMITKO),&opcode,&opcodelen); - if (ret) {} else {printf("Autotest %03d ERROR (out of limit)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing LIMIT 2 OK\n"); - - ret=RasmAssemble(AUTOTEST_LIMIT03,strlen(AUTOTEST_LIMIT03),&opcode,&opcodelen); - if (ret) {} else {printf("Autotest %03d ERROR (limit: negative limit)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing inegative LIMIT OK\n"); - - ret=RasmAssemble(AUTOTEST_LIMIT04,strlen(AUTOTEST_LIMIT04),&opcode,&opcodelen); - if (ret) {} else {printf("Autotest %03d ERROR (limit: max limit test)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing max LIMIT OK\n"); - - ret=RasmAssemble(AUTOTEST_LIMIT05,strlen(AUTOTEST_LIMIT05),&opcode,&opcodelen); - if (ret) {} else {printf("Autotest %03d ERROR (limit: ldir in #FFFF)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing 16 bits opcode overriding LIMIT OK\n"); - - ret=RasmAssemble(AUTOTEST_LIMIT06,strlen(AUTOTEST_LIMIT06),&opcode,&opcodelen); - if (!ret) {} else {printf("Autotest %03d ERROR (limit: nop in #FFFF)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing opcode overriding LIMIT OK\n"); - - ret=RasmAssemble(AUTOTEST_LIMIT07,strlen(AUTOTEST_LIMIT07),&opcode,&opcodelen); - if (ret) {} else {printf("Autotest %03d ERROR (limit: ld hl,#1234 in #FFFF)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing opcode with variable overriding LIMIT OK\n"); - - ret=RasmAssemble(AUTOTEST_DELAYED_RUN,strlen(AUTOTEST_DELAYED_RUN),&opcode,&opcodelen); - if (!ret) {} else {printf("Autotest %03d ERROR (delayed RUN set)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing delayed RUN OK\n"); - - ret=RasmAssemble(AUTOTEST_LZSEGMENT,strlen(AUTOTEST_LZSEGMENT),&opcode,&opcodelen); - if (!ret && opcodelen==23 && opcode[1]==21 && opcode[9]==23) {} else {printf("Autotest %03d ERROR (LZ segment relocation)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing LZ segment relocation OK\n"); - - ret=RasmAssemble(AUTOTEST_LZ4,strlen(AUTOTEST_LZ4),&opcode,&opcodelen); - if (!ret && opcodelen==49 && opcode[0]==0x15 && opcode[4]==0x44 && opcode[0xB]==0xF0) {} else {printf("Autotest %03d ERROR (LZ4 segment)\n",cpt);MiniDump(opcode,opcodelen);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing LZ4 segment OK\n"); - - ret=RasmAssemble(AUTOTEST_DEFS,strlen(AUTOTEST_DEFS),&opcode,&opcodelen); - if (!ret && opcodelen==256 && opcode[0]==0) {} else {printf("Autotest %03d ERROR (defs)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing DEFS OK\n"); - - ret=RasmAssemble(AUTOTEST_BANKSET,strlen(AUTOTEST_BANKSET),&opcode,&opcodelen); - if (!ret) {} else {printf("Autotest %03d ERROR (bank/bankset)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing BANK/BANKSET OK\n"); - - ret=RasmAssemble(AUTOTEST_PAGETAG,strlen(AUTOTEST_PAGETAG),&opcode,&opcodelen); - if (!ret) {} else {printf("Autotest %03d ERROR (page/pageset)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing prefix PAGE/PAGESET 1 OK\n"); - - ret=RasmAssemble(AUTOTEST_PAGETAG2,strlen(AUTOTEST_PAGETAG2),&opcode,&opcodelen); - if (!ret) {} else {printf("Autotest %03d ERROR (page/pageset 2)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing prefix PAGE/PAGESET 2 OK\n"); - - ret=RasmAssemble(AUTOTEST_PAGETAG3,strlen(AUTOTEST_PAGETAG3),&opcode,&opcodelen); - if (!ret) {} else {printf("Autotest %03d ERROR (page/pageset 3)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing prefix PAGE/PAGESET 3 OK\n"); - - ret=RasmAssemble(AUTOTEST_UNDEF,strlen(AUTOTEST_UNDEF),&opcode,&opcodelen); - if (!ret) {} else {printf("Autotest %03d ERROR (simple undef)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing UNDEF OK\n"); - - ret=RasmAssemble(AUTOTEST_TAGPRINT,strlen(AUTOTEST_TAGPRINT),&opcode,&opcodelen); - if (!ret && opcodelen==1 && opcode[0]==0xC9) {} else {printf("Autotest %03d ERROR (tag inside printed string)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing tags inside printed string OK\n"); - - ret=RasmAssemble(AUTOTEST_TAGFOLLOW,strlen(AUTOTEST_TAGFOLLOW),&opcode,&opcodelen); - if (!ret && opcodelen==1 && opcode[0]==0xC9) {} else {printf("Autotest %03d ERROR (tag+alias fast translating)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing tag+alias in fast translate OK\n"); - - ret=RasmAssemble(AUTOTEST_TAGREALLOC,strlen(AUTOTEST_TAGREALLOC),&opcode,&opcodelen); - if (!ret && opcodelen==276) {} else {printf("Autotest %03d ERROR (tag realloc with fast translate)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing tag realloc with fast translate OK\n"); - - ret=RasmAssemble(AUTOTEST_TAGLOOP,strlen(AUTOTEST_TAGLOOP),&opcode,&opcodelen); - if (!ret) {} else {printf("Autotest %03d ERROR (generated alias inside loop with generated var names )\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing generated alias inside loop with generated var names OK\n"); - - ret=RasmAssemble(AUTOTEST_PRINTVAR,strlen(AUTOTEST_PRINTVAR),&opcode,&opcodelen); - if (!ret) {} else {printf("Autotest %03d ERROR (param inside printed string)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing param inside printed string OK\n"); - - ret=RasmAssemble(AUTOTEST_PRINTSPACE,strlen(AUTOTEST_PRINTSPACE),&opcode,&opcodelen); - if (!ret) {} else {printf("Autotest %03d ERROR (space inside tag string for PRINT directive)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing space inside tag string for PRINT directive OK\n"); - - ret=RasmAssemble(AUTOTEST_INHIBITION,strlen(AUTOTEST_INHIBITION),&opcode,&opcodelen); - if (!ret) {} else {printf("Autotest %03d ERROR (conditionnal inhibition)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing conditionnal inhibition OK\n"); - - ret=RasmAssemble(AUTOTEST_SWITCH,strlen(AUTOTEST_SWITCH),&opcode,&opcodelen); - if (!ret && opcodelen==3 && opcode[0]==4 && opcode[1]==3 && opcode[2]==4) {} else {printf("Autotest %03d ERROR (switch case)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing SWITCH/CASE OK\n"); - - ret=RasmAssemble(AUTOTEST_NOCODE,strlen(AUTOTEST_NOCODE),&opcode,&opcodelen); - if (!ret && opcodelen==57) {} else {printf("Autotest %03d ERROR (code/nocode)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing code/nocode OK\n"); - - ret=RasmAssemble(AUTOTEST_VAREQU,strlen(AUTOTEST_VAREQU),&opcode,&opcodelen); - if (!ret) {} else {printf("Autotest %03d ERROR (var & equ)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing var & equ OK\n"); - - ret=RasmAssemble(AUTOTEST_CHARSET,strlen(AUTOTEST_CHARSET),&opcode,&opcodelen); - if (!ret) {} else {printf("Autotest %03d ERROR (simple charset)\n",cpt);exit(-1);} - if (opcodelen!=30 || memcmp(opcode,opcode+5,5) || memcmp(opcode+10,opcode+5,5)) {printf("Autotest %03d ERROR (simple charset)\n",cpt);exit(-1);} - if (memcmp(opcode+15,opcode+20,5) || memcmp(opcode+15,opcode+25,5)) {printf("Autotest %03d ERROR (simple charset)\n",cpt);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing simple charset OK\n"); - - ret=RasmAssemble(AUTOTEST_CHARSET2,strlen(AUTOTEST_CHARSET2),&opcode,&opcodelen); - if (!ret) {} else {printf("Autotest %03d ERROR (extended charset)\n",cpt);exit(-1);} - for (i=chk=0;inberror==2 && debug->nbsymbol==3) { -/* - printf("\n"); - for (i=0;inberror;i++) { - printf("%d -> %s\n",i,debug->error[i].msg); - } - for (i=0;inbsymbol;i++) { - printf("%d -> %s=%d\n",i,debug->symbol[i].name,debug->symbol[i].v); - } - RasmFreeInfoStruct(debug); -*/ - } else {printf("Autotest %03d ERROR (embedded error struct) err=%d nberr=%d (2) nbsymb=%d (3)\n",cpt,ret,debug->nberror,debug->nbsymbol);MiniDump(opcode,opcodelen);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing internal error struct OK\n"); - - ret=RasmAssembleInfo(AUTOTEST_EMBEDDED_LABELS,strlen(AUTOTEST_EMBEDDED_LABELS),&opcode,&opcodelen,&debug); - if (!ret && debug->nbsymbol==3) { - /* - printf("\nnbsymbol=%d\n",debug->nbsymbol); - for (i=0;inbsymbol;i++) { - printf("%d -> %s=%d\n",i,debug->symbol[i].name,debug->symbol[i].v); - }*/ - RasmFreeInfoStruct(debug); - } else {printf("Autotest %03d ERROR (embedded test)\n",cpt);MiniDump(opcode,opcodelen);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; -printf("testing internal label struct OK\n"); - -#ifdef RDD - printf("\n%d bytes\n",_static_library_memory_used); - - tmpstr3=FileReadContent("./test/PlayerAky.asm",&filelen); - printf(".");fflush(stdout);ret=RasmAssembleInfo(tmpstr3,filelen,&opcode,&opcodelen,&debug); - if (!ret) {} else {printf("Autotest %03d ERROR (PlayerAky)\n",cpt);MiniDump(opcode,opcodelen);exit(-1);} - if (opcode) MemFree(opcode);opcode=NULL;cpt++; - RasmFreeInfoStruct(debug); - MemFree(tmpstr3); - - printf("\n%d bytes\n",_static_library_memory_used); -#endif - - FileRemoveIfExists("rasmoutput.cpr"); - - printf("All internal tests OK\n"); - #ifdef RDD - /* private dev lib tools */ -printf("checking memory\n"); - CloseLibrary(); - #endif - exit(0); -} - - -/****************************************************** -LZ48 v005 / LZ49 v002 -******************************************************/ -int LZ48_encode_extended_length(unsigned char *odata, int length) -{ - int ioutput=0; - - while (length>=255) { - odata[ioutput++]=0xFF; - length-=255; - } - /* if the last value is 255 we must encode 0 to end extended length */ - /*if (length==0) rasm_printf(ae,"bugfixed!\n");*/ - odata[ioutput++]=(unsigned char)length; - return ioutput; -} - -int LZ48_encode_block(unsigned char *odata,unsigned char *data, int literaloffset,int literalcpt,int offset,int maxlength) -{ - int ioutput=1; - int token=0; - int i; - - if (offset<0 || offset>255) { - fprintf(stderr,"internal offset error!\n"); - exit(-2); - } - - if (literalcpt<15) { - token=literalcpt<<4; - } else { - token=0xF0; - ioutput+=LZ48_encode_extended_length(odata+ioutput,literalcpt-15); - } - - for (i=0;i2) { - token|=(maxlength-3); - } else { - /* endoffset has no length */ - } - } else { - token|=0xF; - ioutput+=LZ48_encode_extended_length(odata+ioutput,maxlength-18); - } - - odata[ioutput++]=(unsigned char)offset-1; - - odata[0]=(unsigned char)token; - return ioutput; -} - -unsigned char *LZ48_encode_legacy(unsigned char *data, int length, int *retlength) -{ - int i,startscan,current=1,token,ioutput=1,curscan; - int maxoffset=0,maxlength,matchlength,literal=0,literaloffset=1; - unsigned char *odata=NULL; - - odata=MemMalloc((size_t)length*1.5+10); - if (!odata) { - fprintf(stderr,"malloc(%.0lf) - memory full\n",(size_t)length*1.5+10); - exit(-1); - } - - /* first byte always literal */ - odata[0]=data[0]; - - /* force short data encoding */ - if (length<5) { - token=(length-1)<<4; - odata[ioutput++]=(unsigned char)token; - for (i=1;i=3 && matchlength>maxlength) { - maxoffset=startscan; - maxlength=matchlength; - } - startscan++; - } - if (maxlength) { - ioutput+=LZ48_encode_block(odata+ioutput,data,literaloffset,literal,current-maxoffset,maxlength); - current+=maxlength; - literaloffset=current; - literal=0; - } else { - literal++; - current++; - } - } - ioutput+=LZ48_encode_block(odata+ioutput,data,literaloffset,literal,0,0); - *retlength=ioutput; - return odata; -} - -int LZ49_encode_extended_length(unsigned char *odata, int length) -{ - int ioutput=0; - - while (length>=255) { - odata[ioutput++]=0xFF; - length-=255; - } - /* if the last value is 255 we must encode 0 to end extended length */ - /*if (length==0) rasm_printf(ae,"bugfixed!\n");*/ - odata[ioutput++]=(unsigned char)length; - return ioutput; -} - -int LZ49_encode_block(unsigned char *odata,unsigned char *data, int literaloffset,int literalcpt,int offset,int maxlength) -{ - int ioutput=1; - int token=0; - int i; - - if (offset<0 || offset>511) { - fprintf(stderr,"internal offset error!\n"); - exit(-2); - } - - if (literalcpt<7) { - token=literalcpt<<4; - } else { - token=0x70; - ioutput+=LZ49_encode_extended_length(odata+ioutput,literalcpt-7); - } - - for (i=0;i2) { - token|=(maxlength-3); - } else { - /* endoffset has no length */ - } - } else { - token|=0xF; - ioutput+=LZ49_encode_extended_length(odata+ioutput,maxlength-18); - } - - if (offset>255) { - token|=0x80; - offset-=256; - } - odata[ioutput++]=(unsigned char)offset-1; - - odata[0]=(unsigned char)token; - return ioutput; -} - -unsigned char *LZ49_encode_legacy(unsigned char *data, int length, int *retlength) -{ - int i,startscan,current=1,token,ioutput=1,curscan; - int maxoffset=0,maxlength,matchlength,literal=0,literaloffset=1; - unsigned char *odata=NULL; - - odata=MemMalloc((size_t)(length*1.5+10)); - if (!odata) { - fprintf(stderr,"malloc(%.0lf) - memory full\n",(size_t)length*1.5+10); - exit(-1); - } - - /* first byte always literal */ - odata[0]=data[0]; - - /* force short data encoding */ - if (length<5) { - token=(length-1)<<4; - odata[ioutput++]=(unsigned char)token; - for (i=1;i=3 && matchlength>maxlength) { - maxoffset=startscan; - maxlength=matchlength; - } - startscan++; - } - if (maxlength) { - ioutput+=LZ49_encode_block(odata+ioutput,data,literaloffset,literal,current-maxoffset,maxlength); - current+=maxlength; - literaloffset=current; - literal=0; - } else { - literal++; - current++; - } - } - ioutput+=LZ49_encode_block(odata+ioutput,data,literaloffset,literal,0,0); - *retlength=ioutput; - return odata; -} - - -/*************************************** - semi-generic body of program -***************************************/ - -#ifndef INTEGRATED_ASSEMBLY - -/* - Usage - display the mandatory parameters -*/ -void Usage(int help) -{ - #undef FUNC - #define FUNC "Usage" - - printf("%s (c) 2017 Edouard BERGE (use -n option to display all licenses)\n",RASM_VERSION); - #ifndef NO_3RD_PARTIES - printf("LZ4 (c) Yann Collet / ZX7 (c) Einar Saukas / Exomizer 2 (c) Magnus Lind\n"); - #endif - printf("\n"); - printf("SYNTAX: rasm [options]\n"); - printf("\n"); - - if (help) { - printf("FILENAMES:\n"); - printf("-oa automatic radix from input filename\n"); - printf("-o choose a common radix for all files\n"); - printf("-ob choose a full filename for binary output\n"); - printf("-oc choose a full filename for cartridge output\n"); - printf("-oi choose a full filename for snapshot output\n"); - printf("-os choose a full filename for symbol output\n"); - printf("-ot choose a full filename for tape output\n"); - printf("-ok choose a full filename for breakpoint output\n"); - printf("-I set a path for files to read\n"); - printf("-no disable all file output\n"); - printf("DEPENDENCIES EXPORT:\n"); - printf("-depend=make output dependencies on a single line\n"); - printf("-depend=list output dependencies as a list\n"); - printf("if 'binary filename' is set then it will be outputed first\n"); - printf("SYMBOLS EXPORT:\n"); - printf("-s export symbols %%s #%%X B%%d (label,adr,cprbank)\n"); - printf("-sz export symbols with ZX emulator convention\n"); - printf("-sp export symbols with Pasmo convention\n"); - printf("-sw export symbols with Winape convention\n"); - printf("-ss export symbols in the snapshot (SYMB chunk for ACE)\n"); - printf("-sc export symbols with source code convention\n"); - printf("-sm export symbol in multiple files (one per bank)\n"); - printf("-l import symbol file (winape,pasmo,rasm)\n"); - printf("-eb export breakpoints\n"); - printf("-wu warn for unused symbols (alias, var or label)\n"); - printf("SYMBOLS ADDITIONAL OPTIONS:\n"); - printf("-sl export also local symbol\n"); - printf("-sv export also variables symbol\n"); - printf("-sq export also EQU symbol\n"); - printf("-sa export all symbols (like -sl -sv -sq option)\n"); - printf("-Dvariable=value import value for variable\n"); - printf("COMPATIBILITY:\n"); - printf("-m Maxam style calculations\n"); - printf("-dams Dams 'dot' label convention\n"); - printf("-ass AS80 behaviour mimic\n"); - printf("-uz UZ80 behaviour mimic\n"); - - printf("EDSK generation/update:\n"); - printf("-eo overwrite files on disk if it already exists\n"); - printf("SNAPSHOT:\n"); - printf("-sb export breakpoints in snapshot (BRKS & BRKC chunks)\n"); - printf("-ss export symbols in the snapshot (SYMB chunk for ACE)\n"); - printf("-v2 export snapshot version 2 instead of version 3\n"); - printf("PARSING:\n"); - printf("-me set maximum number of error (0 means no limit)\n"); - printf("-xr extended error display\n"); - printf("-w disable warnings\n"); - printf("-void force void usage with macro without parameter\n"); - printf("\n"); - } else { - printf("use option -h for help\n"); - printf("\n"); - } - - exit(ABORT_ERROR); -} - -void Licenses() -{ - #undef FUNC - #define FUNC "Licenses" - -printf(" ____ \n"); -printf(" | _ \\ __ _ ___ _ __ ___ \n"); -printf(" | |_) / _` / __| '_ ` _ \\ \n"); -printf(" | _ < (_| \\__ \\ | | | | |\n"); -printf(" |_| \\_\\__,_|___/_| |_| |_|\n"); -printf("\n"); -printf(" is using MIT 'expat' license\n"); -printf("\" Copyright (c) BERGE Edouard (roudoudou)\n\n"); - -printf("Permission is hereby granted, free of charge,\n"); -printf("to any person obtaining a copy of this software\n"); -printf("and associated documentation/source files of\n"); -printf("RASM, to deal in the Software without restriction,\n"); -printf("including without limitation the rights to use,\n"); -printf("copy, modify, merge, publish, distribute,\n"); -printf("sublicense, and/or sell copies of the Software,\n"); -printf("and to permit persons to whom the Software is\n"); -printf("furnished to do so, subject to the following\n"); -printf("conditions:\n"); - -printf("The above copyright notice and this permission\n"); -printf("notice shall be included in all copies or\n"); -printf("substantial portions of the Software.\n"); -printf("The Software is provided 'as is', without\n"); -printf("warranty of any kind, express or implied,\n"); -printf("including but not limited to the warranties of\n"); -printf("merchantability, fitness for a particular\n"); -printf("purpose and noninfringement. In no event shall\n"); -printf("the authors or copyright holders be liable for\n"); -printf("any claim, damages or other liability, whether\n"); -printf("in an action of contract, tort or otherwise,\n"); -printf("arising from, out of or in connection with the\n"); -printf("software or the use or other dealings in the\n"); -printf("Software. \"\n"); - -#ifndef NO_3RD_PARTIES -printf("\n\n\n\n"); -printf("******* license of LZ4 cruncher / sources were modified ***********\n\n\n\n"); - -printf("BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)\n"); - -printf("Redistribution and use in source and binary forms, with or without\n"); -printf("modification, are permitted provided that the following conditions are\n"); -printf("met:\n\n"); - -printf(" * Redistributions of source code must retain the above copyright\n"); -printf("notice, this list of conditions and the following disclaimer.\n"); -printf(" * Redistributions in binary form must reproduce the above\n"); -printf("copyright notice, this list of conditions and the following disclaimer\n"); -printf("in the documentation and/or other materials provided with the\n"); -printf("distribution.\n\n"); - -printf("THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"); -printf("'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"); -printf("LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"); -printf("A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"); -printf("OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"); -printf("SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"); -printf("LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"); -printf("DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"); -printf("THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"); -printf("(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"); -printf("OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n"); - -printf("You can contact the author at :\n"); -printf(" - LZ4 homepage : http://www.lz4.org\n"); -printf(" - LZ4 source repository : https://github.com/lz4/lz4\n"); - - -printf("\n\n\n\n"); -printf("******* license of ZX7 cruncher / sources were modified ***********\n\n\n\n"); - - -printf(" * (c) Copyright 2012 by Einar Saukas. All rights reserved.\n"); -printf(" *\n"); -printf(" * Redistribution and use in source and binary forms, with or without\n"); -printf(" * modification, are permitted provided that the following conditions are met:\n"); -printf(" * * Redistributions of source code must retain the above copyright\n"); -printf(" * notice, this list of conditions and the following disclaimer.\n"); -printf(" * * Redistributions in binary form must reproduce the above copyright\n"); -printf(" * notice, this list of conditions and the following disclaimer in the\n"); -printf(" * documentation and/or other materials provided with the distribution.\n"); -printf(" * * The name of its author may not be used to endorse or promote products\n"); -printf(" * derived from this software without specific prior written permission.\n"); -printf(" *\n"); -printf(" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND\n"); -printf(" * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n"); -printf(" * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n"); -printf(" * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY\n"); -printf(" * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n"); -printf(" * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n"); -printf(" * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n"); -printf(" * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"); -printf(" * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n"); -printf(" * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"); - - -printf("\n\n\n\n"); -printf("******* license of exomizer cruncher / sources were modified ***********\n\n\n\n"); - - -printf(" * Copyright (c) 2005 Magnus Lind.\n"); -printf(" *\n"); -printf(" * This software is provided 'as-is', without any express or implied warranty.\n"); -printf(" * In no event will the authors be held liable for any damages arising from\n"); -printf(" * the use of this software.\n"); -printf(" *\n"); -printf(" * Permission is granted to anyone to use this software, alter it and re-\n"); -printf(" * distribute it freely for any non-commercial, non-profit purpose subject to\n"); -printf(" * the following restrictions:\n"); -printf(" *\n"); -printf(" * 1. The origin of this software must not be misrepresented; you must not\n"); -printf(" * claim that you wrote the original software. If you use this software in a\n"); -printf(" * product, an acknowledgment in the product documentation would be\n"); -printf(" * appreciated but is not required.\n"); -printf(" *\n"); -printf(" * 2. Altered source versions must be plainly marked as such, and must not\n"); -printf(" * be misrepresented as being the original software.\n"); -printf(" *\n"); -printf(" * 3. This notice may not be removed or altered from any distribution.\n"); -printf(" *\n"); -printf(" * 4. The names of this software and/or it's copyright holders may not be\n"); -printf(" * used to endorse or promote products derived from this software without\n"); -printf(" * specific prior written permission.\n"); -#endif - -printf("\n\n"); - - - - exit(0); -} - -int _internal_check_flexible(char *fxp) { - #undef FUNC - #define FUNC "_internal_check_flexible" - - char *posval,*posvar; - int cpt=0,i; - - posvar=strstr(fxp,"%s"); - posval=strstr(fxp,"%"); - if (!posval || !posvar) { - printf("invalid flexible export string, need 2 formated fields, example: \"%%s %%d\"\n"); - exit(1); - } - if (posval2) { - printf("invalid flexible export string, must be only two formated fields, example: \"%%s %%d\"\n"); - exit(1); - } - - return 1; -} -/* - ParseOptions - - used to parse command line and configuration file -*/ -int ParseOptions(char **argv,int argc, struct s_parameter *param) -{ - #undef FUNC - #define FUNC "ParseOptions" - - char *sep; - int i=0; - - if (strcmp(argv[i],"-autotest")==0) { - RasmAutotest(); - } else if (strcmp(argv[i],"-uz")==0) { - param->as80=2; - } else if (strcmp(argv[i],"-ass")==0) { - param->as80=1; - } else if (strcmp(argv[i],"-eb")==0) { - param->export_brk=1; - } else if (strcmp(argv[i],"-wu")==0) { - param->warn_unused=1; - } else if (strcmp(argv[i],"-dams")==0) { - } else if (strcmp(argv[i],"-void")==0) { - param->macrovoid=1; - } else if (strcmp(argv[i],"-xr")==0) { - param->extended_error=1; - } else if (strcmp(argv[i],"-eo")==0) { - param->edskoverwrite=1; - } else if (strcmp(argv[i],"-depend=make")==0) { - param->dependencies=E_DEPENDENCIES_MAKE; - param->checkmode=1; - } else if (strcmp(argv[i],"-depend=list")==0) { - param->dependencies=E_DEPENDENCIES_LIST; - param->checkmode=1; - } else if (strcmp(argv[i],"-no")==0) { - param->checkmode=1; - } else if (strcmp(argv[i],"-w")==0) { - param->nowarning=1; - } else if (argv[i][0]=='-') { - switch(argv[i][1]) - { - case 'I': - if (argv[i][2]) { - char *curpath; - int l; - l=strlen(argv[i]); - curpath=MemMalloc(l); /* strlen(path)+2 */ - strcpy(curpath,argv[i]+2); -#ifdef OS_WIN - if (argv[i][l-1]!='/' && argv[i][l-1]!='\\') strcat(curpath,"\\"); -#else - if (argv[i][l-1]!='/' && argv[i][l-1]!='\\') strcat(curpath,"/"); -#endif - FieldArrayAddDynamicValueConcat(¶m->pathdef,¶m->npath,¶m->mpath,curpath); - MemFree(curpath); - } else { - Usage(1); - } - break; - case 'D': - if ((sep=strchr(argv[i],'='))!=NULL) { - if (sep!=argv[i]+2) { - FieldArrayAddDynamicValueConcat(¶m->symboldef,¶m->nsymb,¶m->msymb,argv[i]+2); - } else { - Usage(1); - } - } else { - Usage(1); - } - break; - case 'm': - switch (argv[i][2]) { - case 0: - param->rough=0.0; - return i; - case 'e': - if (argv[i][3]) Usage(1); - if (i+1maxerr=atoi(argv[++i]); - return i; - } - default:Usage(1); - } - Usage(1); - break; - case 's': - if (argv[i][2] && argv[i][3]) Usage(1); - switch (argv[i][2]) { - case 0:param->export_sym=1;return 0; - case 'z': - param->export_sym=5;return 0; - case 'm': - param->export_multisym=1;return 0; - case 'b': - param->export_snabrk=1;return 0; - case 'p': - param->export_sym=2;return 0; - case 'w': - param->export_sym=3;return 0; - case 'c': - if (i+1export_sym=4; - param->flexible_export=TxtStrDup(argv[++i]); - param->flexible_export=MemRealloc(param->flexible_export,strlen(param->flexible_export)+3); - strcat(param->flexible_export,"\n"); - /* check export string */ - if (_internal_check_flexible(param->flexible_export)) return i; else Usage(1); - } - Usage(1); - case 'l': - param->export_local=1;return 0; - case 'v': - param->export_var=1;return 0; - case 'q': - param->export_equ=1;return 0; - case 'a': - param->export_local=1; - param->export_var=1; - param->export_equ=1; - return 0; - case 's': - param->export_local=1; - param->export_sym=1; - param->export_sna=1;return 0; - default: - break; - } - Usage(1); - case 'l': - if (argv[i][2]) Usage(1); - if (i+1labelfilename,argv[++i]); - break; - } - Usage(1); - case 'i': -printf("@@@\n@@@ --> deprecated option, there is no need to use -i option to set input file <--\n@@@\n"); - Usage(0); - case 'o': - if (argv[i][2] && argv[i][3]) Usage(1); - switch (argv[i][2]) { - case 0: - if (i+1outputfilename==NULL) { - param->outputfilename=argv[++i]; - break; - } - Usage(1); - case 'a': - param->automatic_radix=1; - break; - case 't': - if (i+1tape_name==NULL) { - param->tape_name=argv[++i]; - break; - } - Usage(1); - case 'i': - if (i+1snapshot_name==NULL) { - param->snapshot_name=argv[++i]; - break; - } - Usage(1); - case 'b': - if (i+1binary_name==NULL) { - param->binary_name=argv[++i]; - break; - } - Usage(1); - case 'c': - if (i+1cartridge_name==NULL) { - param->cartridge_name=argv[++i]; - break; - } - Usage(1); - case 'k': - if (i+1breakpoint_name==NULL) { - param->breakpoint_name=argv[++i]; - break; - } - Usage(1); - case 's': - if (i+1symbol_name==NULL) { - param->symbol_name=argv[++i]; - break; - } - Usage(1); - default: - Usage(1); - } - break; - case 'd':if (!argv[i][2]) printf("deprecated option -d\n"); else Usage(1); - break; - case 'a':if (!argv[i][2]) printf("deprecated option -a\n"); else Usage(1); - break; - case 'c':if (!argv[i][2]) printf("deprecated option -c\n"); else Usage(1); - break; - case 'v': - if (!argv[i][2]) { - printf("deprecated option -v\n"); - } else if (argv[i][2]=='2') { - param->v2=1; - } - break; - case 'n':if (!argv[i][2]) Licenses(); else Usage(1); - case 'h':Usage(1); - default: - Usage(1); - } - } else { - if (param->filename==NULL) { - param->filename=TxtStrDup(argv[i]); - } else if (param->outputfilename==NULL) { - param->outputfilename=argv[i]; - } else Usage(1); - } - return i; -} - -/* - GetParametersFromCommandLine - retrieve parameters from command line and fill pointers to file names -*/ -void GetParametersFromCommandLine(int argc, char **argv, struct s_parameter *param) -{ - #undef FUNC - #define FUNC "GetParametersFromCommandLine" - int i; - - for (i=1;ifilename) Usage(0); - if (param->export_local && !param->export_sym) Usage(1); // à revoir? -} - -/* - main - - check parameters - execute the main processing -*/ - - -int main(int argc, char **argv) -{ - #undef FUNC - #define FUNC "main" - - struct s_parameter param={0}; - int ret; - - param.maxerr=20; - param.rough=0.5; - - GetParametersFromCommandLine(argc,argv,¶m); - ret=Rasm(¶m); - #ifdef RDD - /* private dev lib tools */ -printf("checking memory\n"); - CloseLibrary(); - #endif - exit(ret); - return 0; // Open WATCOM Warns without this... -} - -#endif - - diff --git a/tools/rasm/resources/opcodes_first_byte.asm b/tools/rasm/resources/opcodes_first_byte.asm new file mode 100644 index 0000000..6a6e21b --- /dev/null +++ b/tools/rasm/resources/opcodes_first_byte.asm @@ -0,0 +1,542 @@ +;; This file was generated with the help of a bash script. +;; The use case was mentioned by user https://github.com/rgiot on +;; https://github.com/EdouardBERGE/rasm/issues/2 + +;; When you need the value of a Z80 instruction, e.g. for any purpose +;; handling instructions, like analyzing or generating code, your code +;; might look like this: +;; +;; ld a, 0xe1 ; POP HL but this comment might be out of date +;; ld (somelabel), a +;; +;; This file allows you something more readable and maintainable: +;; +;; include "opcodes_first_byte.asm" +;; ...your code... +;; ld a, opcode_pop_hl +;; ld (somelabel), a +;; +;; which is better because you are certain about what the code does. +;; +;; Still better, if your editor allows auto-completion, you may +;; autocomplete it to the explicit value: +;; +;; ld a, opcode_pop_hl_0xe1 +;; ld (somelabel), a +;; +;; This way, both the code meaning and the numeric opcode value are +;; visible in your source code, and they will always be in sync. + +;; The script is in +;; cpc-dev-tool-chain/documentation-for-maintainers/z80_data_transform/generate_names_for_first_byte_of_ops.sh +;; The script uses data published at https://borilla.co.uk/z80.html . Thanks John +;; Adams a.k.a. https://github.com/borilla ! + +;; The list below is in alphabetical order of macro. +;; If you have a GNU environment, you can sort it by op code with: + +opcode_adc_a_a_0x8f EQU 0x8f +opcode_adc_a_a EQU 0x8f +opcode_adc_a_b_0x88 EQU 0x88 +opcode_adc_a_b EQU 0x88 +opcode_adc_a_c_0x89 EQU 0x89 +opcode_adc_a_c EQU 0x89 +opcode_adc_a_d_0x8a EQU 0x8a +opcode_adc_a_d EQU 0x8a +opcode_adc_a_e_0x8b EQU 0x8b +opcode_adc_a_e EQU 0x8b +opcode_adc_a_h_0x8c EQU 0x8c +opcode_adc_a_h EQU 0x8c +opcode_adc_a_hl_0x8e EQU 0x8e +opcode_adc_a_hl EQU 0x8e +opcode_adc_a_l_0x8d EQU 0x8d +opcode_adc_a_l EQU 0x8d +opcode_adc_a_nn_0xce EQU 0xce +opcode_adc_a_nn EQU 0xce +opcode_add_a_a_0x87 EQU 0x87 +opcode_add_a_a EQU 0x87 +opcode_add_a_b_0x80 EQU 0x80 +opcode_add_a_b EQU 0x80 +opcode_add_a_c_0x81 EQU 0x81 +opcode_add_a_c EQU 0x81 +opcode_add_a_d_0x82 EQU 0x82 +opcode_add_a_d EQU 0x82 +opcode_add_a_e_0x83 EQU 0x83 +opcode_add_a_e EQU 0x83 +opcode_add_a_h_0x84 EQU 0x84 +opcode_add_a_h EQU 0x84 +opcode_add_a_hl_0x86 EQU 0x86 +opcode_add_a_hl EQU 0x86 +opcode_add_a_l_0x85 EQU 0x85 +opcode_add_a_l EQU 0x85 +opcode_add_a_nn_0xc6 EQU 0xc6 +opcode_add_a_nn EQU 0xc6 +opcode_add_hl_bc_0x09 EQU 0x09 +opcode_add_hl_bc EQU 0x09 +opcode_add_hl_de_0x19 EQU 0x19 +opcode_add_hl_de EQU 0x19 +opcode_add_hl_hl_0x29 EQU 0x29 +opcode_add_hl_hl EQU 0x29 +opcode_add_hl_sp_0x39 EQU 0x39 +opcode_add_hl_sp EQU 0x39 +opcode_and_a_0xa7 EQU 0xa7 +opcode_and_a EQU 0xa7 +opcode_and_b_0xa0 EQU 0xa0 +opcode_and_b EQU 0xa0 +opcode_and_c_0xa1 EQU 0xa1 +opcode_and_c EQU 0xa1 +opcode_and_d_0xa2 EQU 0xa2 +opcode_and_d EQU 0xa2 +opcode_and_e_0xa3 EQU 0xa3 +opcode_and_e EQU 0xa3 +opcode_and_h_0xa4 EQU 0xa4 +opcode_and_h EQU 0xa4 +opcode_and_hl_0xa6 EQU 0xa6 +opcode_and_hl EQU 0xa6 +opcode_and_l_0xa5 EQU 0xa5 +opcode_and_l EQU 0xa5 +opcode_and_nn_0xe6 EQU 0xe6 +opcode_and_nn EQU 0xe6 +opcode_call_c_nnnn_0xdc EQU 0xdc +opcode_call_c_nnnn EQU 0xdc +opcode_call_m_nnnn_0xfc EQU 0xfc +opcode_call_m_nnnn EQU 0xfc +opcode_call_nc_nnnn_0xd4 EQU 0xd4 +opcode_call_nc_nnnn EQU 0xd4 +opcode_call_nnnn_0xcd EQU 0xcd +opcode_call_nnnn EQU 0xcd +opcode_call_nz_nnnn_0xc4 EQU 0xc4 +opcode_call_nz_nnnn EQU 0xc4 +opcode_call_pe_nnnn_0xec EQU 0xec +opcode_call_pe_nnnn EQU 0xec +opcode_call_p_nnnn_0xf4 EQU 0xf4 +opcode_call_p_nnnn EQU 0xf4 +opcode_call_po_nnnn_0xe4 EQU 0xe4 +opcode_call_po_nnnn EQU 0xe4 +opcode_call_z_nnnn_0xcc EQU 0xcc +opcode_call_z_nnnn EQU 0xcc +opcode_ccf_0x3f EQU 0x3f +opcode_ccf EQU 0x3f +opcode_cp_a_0xbf EQU 0xbf +opcode_cp_a EQU 0xbf +opcode_cp_b_0xb8 EQU 0xb8 +opcode_cp_b EQU 0xb8 +opcode_cp_c_0xb9 EQU 0xb9 +opcode_cp_c EQU 0xb9 +opcode_cp_d_0xba EQU 0xba +opcode_cp_d EQU 0xba +opcode_cp_e_0xbb EQU 0xbb +opcode_cp_e EQU 0xbb +opcode_cp_h_0xbc EQU 0xbc +opcode_cp_h EQU 0xbc +opcode_cp_hl_0xbe EQU 0xbe +opcode_cp_hl EQU 0xbe +opcode_cpl_0x2f EQU 0x2f +opcode_cp_l_0xbd EQU 0xbd +opcode_cpl EQU 0x2f +opcode_cp_l EQU 0xbd +opcode_cp_nn_0xfe EQU 0xfe +opcode_cp_nn EQU 0xfe +opcode_daa_0x27 EQU 0x27 +opcode_daa EQU 0x27 +opcode_dec_a_0x3d EQU 0x3d +opcode_dec_a EQU 0x3d +opcode_dec_b_0x05 EQU 0x05 +opcode_dec_bc_0x0b EQU 0x0b +opcode_dec_bc EQU 0x0b +opcode_dec_b EQU 0x05 +opcode_dec_c_0x0d EQU 0x0d +opcode_dec_c EQU 0x0d +opcode_dec_d_0x15 EQU 0x15 +opcode_dec_de_0x1b EQU 0x1b +opcode_dec_de EQU 0x1b +opcode_dec_d EQU 0x15 +opcode_dec_e_0x1d EQU 0x1d +opcode_dec_e EQU 0x1d +opcode_dec_h_0x25 EQU 0x25 +opcode_dec_h EQU 0x25 +opcode_dec_hl_0x2b EQU 0x2b +opcode_dec_hl_0x35 EQU 0x35 +opcode_dec_hl EQU 0x2b +opcode_dec_hl EQU 0x35 +opcode_dec_l_0x2d EQU 0x2d +opcode_dec_l EQU 0x2d +opcode_dec_sp_0x3b EQU 0x3b +opcode_dec_sp EQU 0x3b +opcode_di_0xf3 EQU 0xf3 +opcode_di EQU 0xf3 +opcode_djnz_nn_0x10 EQU 0x10 +opcode_djnz_nn EQU 0x10 +opcode_ei_0xfb EQU 0xfb +opcode_ei EQU 0xfb +opcode_ex_af_af_0x08 EQU 0x08 +opcode_ex_af_af EQU 0x08 +opcode_ex_de_hl_0xeb EQU 0xeb +opcode_ex_de_hl EQU 0xeb +opcode_ex_sp_hl_0xe3 EQU 0xe3 +opcode_ex_sp_hl EQU 0xe3 +opcode_exx_0xd9 EQU 0xd9 +opcode_exx EQU 0xd9 +opcode_halt_0x76 EQU 0x76 +opcode_halt EQU 0x76 +opcode_in_a_nn_0xdb EQU 0xdb +opcode_in_a_nn EQU 0xdb +opcode_inc_a_0x3c EQU 0x3c +opcode_inc_a EQU 0x3c +opcode_inc_b_0x04 EQU 0x04 +opcode_inc_bc_0x03 EQU 0x03 +opcode_inc_bc EQU 0x03 +opcode_inc_b EQU 0x04 +opcode_inc_c_0x0c EQU 0x0c +opcode_inc_c EQU 0x0c +opcode_inc_d_0x14 EQU 0x14 +opcode_inc_de_0x13 EQU 0x13 +opcode_inc_de EQU 0x13 +opcode_inc_d EQU 0x14 +opcode_inc_e_0x1c EQU 0x1c +opcode_inc_e EQU 0x1c +opcode_inc_h_0x24 EQU 0x24 +opcode_inc_h EQU 0x24 +opcode_inc_hl_0x23 EQU 0x23 +opcode_inc_hl_0x34 EQU 0x34 +opcode_inc_hl EQU 0x23 +opcode_inc_hl EQU 0x34 +opcode_inc_l_0x2c EQU 0x2c +opcode_inc_l EQU 0x2c +opcode_inc_sp_0x33 EQU 0x33 +opcode_inc_sp EQU 0x33 +opcode_jp_c_nnnn_0xda EQU 0xda +opcode_jp_c_nnnn EQU 0xda +opcode_jp_hl_0xe9 EQU 0xe9 +opcode_jp_hl EQU 0xe9 +opcode_jp_m_nnnn_0xfa EQU 0xfa +opcode_jp_m_nnnn EQU 0xfa +opcode_jp_nc_nnnn_0xd2 EQU 0xd2 +opcode_jp_nc_nnnn EQU 0xd2 +opcode_jp_nnnn_0xc3 EQU 0xc3 +opcode_jp_nnnn EQU 0xc3 +opcode_jp_nz_nnnn_0xc2 EQU 0xc2 +opcode_jp_nz_nnnn EQU 0xc2 +opcode_jp_pe_nnnn_0xea EQU 0xea +opcode_jp_pe_nnnn EQU 0xea +opcode_jp_p_nnnn_0xf2 EQU 0xf2 +opcode_jp_p_nnnn EQU 0xf2 +opcode_jp_po_nnnn_0xe2 EQU 0xe2 +opcode_jp_po_nnnn EQU 0xe2 +opcode_jp_z_nnnn_0xca EQU 0xca +opcode_jp_z_nnnn EQU 0xca +opcode_jr_c_nn_0x38 EQU 0x38 +opcode_jr_c_nn EQU 0x38 +opcode_jr_nc_nn_0x30 EQU 0x30 +opcode_jr_nc_nn EQU 0x30 +opcode_jr_nn_0x18 EQU 0x18 +opcode_jr_nn EQU 0x18 +opcode_jr_nz_nn_0x20 EQU 0x20 +opcode_jr_nz_nn EQU 0x20 +opcode_jr_z_nn_0x28 EQU 0x28 +opcode_jr_z_nn EQU 0x28 +opcode_ld_a_a_0x7f EQU 0x7f +opcode_ld_a_a EQU 0x7f +opcode_ld_a_b_0x78 EQU 0x78 +opcode_ld_a_bc_0x0a EQU 0x0a +opcode_ld_a_bc EQU 0x0a +opcode_ld_a_b EQU 0x78 +opcode_ld_a_c_0x79 EQU 0x79 +opcode_ld_a_c EQU 0x79 +opcode_ld_a_d_0x7a EQU 0x7a +opcode_ld_a_de_0x1a EQU 0x1a +opcode_ld_a_de EQU 0x1a +opcode_ld_a_d EQU 0x7a +opcode_ld_a_e_0x7b EQU 0x7b +opcode_ld_a_e EQU 0x7b +opcode_ld_a_h_0x7c EQU 0x7c +opcode_ld_a_h EQU 0x7c +opcode_ld_a_hl_0x7e EQU 0x7e +opcode_ld_a_hl EQU 0x7e +opcode_ld_a_l_0x7d EQU 0x7d +opcode_ld_a_l EQU 0x7d +opcode_ld_a_nn_0x3e EQU 0x3e +opcode_ld_a_nn EQU 0x3e +opcode_ld_a_nnnn_0x3a EQU 0x3a +opcode_ld_a_nnnn EQU 0x3a +opcode_ld_b_a_0x47 EQU 0x47 +opcode_ld_b_a EQU 0x47 +opcode_ld_b_b_0x40 EQU 0x40 +opcode_ld_b_b EQU 0x40 +opcode_ld_b_c_0x41 EQU 0x41 +opcode_ld_bc_a_0x02 EQU 0x02 +opcode_ld_bc_a EQU 0x02 +opcode_ld_b_c EQU 0x41 +opcode_ld_bc_nnnn_0x01 EQU 0x01 +opcode_ld_bc_nnnn EQU 0x01 +opcode_ld_b_d_0x42 EQU 0x42 +opcode_ld_b_d EQU 0x42 +opcode_ld_b_e_0x43 EQU 0x43 +opcode_ld_b_e EQU 0x43 +opcode_ld_b_h_0x44 EQU 0x44 +opcode_ld_b_h EQU 0x44 +opcode_ld_b_hl_0x46 EQU 0x46 +opcode_ld_b_hl EQU 0x46 +opcode_ld_b_l_0x45 EQU 0x45 +opcode_ld_b_l EQU 0x45 +opcode_ld_b_nn_0x06 EQU 0x06 +opcode_ld_b_nn EQU 0x06 +opcode_ld_c_a_0x4f EQU 0x4f +opcode_ld_c_a EQU 0x4f +opcode_ld_c_b_0x48 EQU 0x48 +opcode_ld_c_b EQU 0x48 +opcode_ld_c_c_0x49 EQU 0x49 +opcode_ld_c_c EQU 0x49 +opcode_ld_c_d_0x4a EQU 0x4a +opcode_ld_c_d EQU 0x4a +opcode_ld_c_e_0x4b EQU 0x4b +opcode_ld_c_e EQU 0x4b +opcode_ld_c_h_0x4c EQU 0x4c +opcode_ld_c_h EQU 0x4c +opcode_ld_c_hl_0x4e EQU 0x4e +opcode_ld_c_hl EQU 0x4e +opcode_ld_c_l_0x4d EQU 0x4d +opcode_ld_c_l EQU 0x4d +opcode_ld_c_nn_0x0e EQU 0x0e +opcode_ld_c_nn EQU 0x0e +opcode_ld_d_a_0x57 EQU 0x57 +opcode_ld_d_a EQU 0x57 +opcode_ld_d_b_0x50 EQU 0x50 +opcode_ld_d_b EQU 0x50 +opcode_ld_d_c_0x51 EQU 0x51 +opcode_ld_d_c EQU 0x51 +opcode_ld_d_d_0x52 EQU 0x52 +opcode_ld_d_d EQU 0x52 +opcode_ld_d_e_0x53 EQU 0x53 +opcode_ld_de_a_0x12 EQU 0x12 +opcode_ld_de_a EQU 0x12 +opcode_ld_d_e EQU 0x53 +opcode_ld_de_nnnn_0x11 EQU 0x11 +opcode_ld_de_nnnn EQU 0x11 +opcode_ld_d_h_0x54 EQU 0x54 +opcode_ld_d_h EQU 0x54 +opcode_ld_d_hl_0x56 EQU 0x56 +opcode_ld_d_hl EQU 0x56 +opcode_ld_d_l_0x55 EQU 0x55 +opcode_ld_d_l EQU 0x55 +opcode_ld_d_nn_0x16 EQU 0x16 +opcode_ld_d_nn EQU 0x16 +opcode_ld_e_a_0x5f EQU 0x5f +opcode_ld_e_a EQU 0x5f +opcode_ld_e_b_0x58 EQU 0x58 +opcode_ld_e_b EQU 0x58 +opcode_ld_e_c_0x59 EQU 0x59 +opcode_ld_e_c EQU 0x59 +opcode_ld_e_d_0x5a EQU 0x5a +opcode_ld_e_d EQU 0x5a +opcode_ld_e_e_0x5b EQU 0x5b +opcode_ld_e_e EQU 0x5b +opcode_ld_e_h_0x5c EQU 0x5c +opcode_ld_e_h EQU 0x5c +opcode_ld_e_hl_0x5e EQU 0x5e +opcode_ld_e_hl EQU 0x5e +opcode_ld_e_l_0x5d EQU 0x5d +opcode_ld_e_l EQU 0x5d +opcode_ld_e_nn_0x1e EQU 0x1e +opcode_ld_e_nn EQU 0x1e +opcode_ld_h_a_0x67 EQU 0x67 +opcode_ld_h_a EQU 0x67 +opcode_ld_h_b_0x60 EQU 0x60 +opcode_ld_h_b EQU 0x60 +opcode_ld_h_c_0x61 EQU 0x61 +opcode_ld_h_c EQU 0x61 +opcode_ld_h_d_0x62 EQU 0x62 +opcode_ld_h_d EQU 0x62 +opcode_ld_h_e_0x63 EQU 0x63 +opcode_ld_h_e EQU 0x63 +opcode_ld_h_h_0x64 EQU 0x64 +opcode_ld_h_h EQU 0x64 +opcode_ld_h_hl_0x66 EQU 0x66 +opcode_ld_h_hl EQU 0x66 +opcode_ld_h_l_0x65 EQU 0x65 +opcode_ld_hl_a_0x77 EQU 0x77 +opcode_ld_hl_a EQU 0x77 +opcode_ld_hl_b_0x70 EQU 0x70 +opcode_ld_hl_b EQU 0x70 +opcode_ld_hl_c_0x71 EQU 0x71 +opcode_ld_hl_c EQU 0x71 +opcode_ld_hl_d_0x72 EQU 0x72 +opcode_ld_hl_d EQU 0x72 +opcode_ld_hl_e_0x73 EQU 0x73 +opcode_ld_hl_e EQU 0x73 +opcode_ld_h_l EQU 0x65 +opcode_ld_hl_h_0x74 EQU 0x74 +opcode_ld_hl_h EQU 0x74 +opcode_ld_hl_l_0x75 EQU 0x75 +opcode_ld_hl_l EQU 0x75 +opcode_ld_hl_nn_0x36 EQU 0x36 +opcode_ld_hl_nn EQU 0x36 +opcode_ld_hl_nnnn_0x21 EQU 0x21 +opcode_ld_hl_nnnn_0x2a EQU 0x2a +opcode_ld_hl_nnnn EQU 0x21 +opcode_ld_hl_nnnn EQU 0x2a +opcode_ld_h_nn_0x26 EQU 0x26 +opcode_ld_h_nn EQU 0x26 +opcode_ld_l_a_0x6f EQU 0x6f +opcode_ld_l_a EQU 0x6f +opcode_ld_l_b_0x68 EQU 0x68 +opcode_ld_l_b EQU 0x68 +opcode_ld_l_c_0x69 EQU 0x69 +opcode_ld_l_c EQU 0x69 +opcode_ld_l_d_0x6a EQU 0x6a +opcode_ld_l_d EQU 0x6a +opcode_ld_l_e_0x6b EQU 0x6b +opcode_ld_l_e EQU 0x6b +opcode_ld_l_h_0x6c EQU 0x6c +opcode_ld_l_h EQU 0x6c +opcode_ld_l_hl_0x6e EQU 0x6e +opcode_ld_l_hl EQU 0x6e +opcode_ld_l_l_0x6d EQU 0x6d +opcode_ld_l_l EQU 0x6d +opcode_ld_l_nn_0x2e EQU 0x2e +opcode_ld_l_nn EQU 0x2e +opcode_ld_nnnn_a_0x32 EQU 0x32 +opcode_ld_nnnn_a EQU 0x32 +opcode_ld_nnnn_hl_0x22 EQU 0x22 +opcode_ld_nnnn_hl EQU 0x22 +opcode_ld_sp_hl_0xf9 EQU 0xf9 +opcode_ld_sp_hl EQU 0xf9 +opcode_ld_sp_nnnn_0x31 EQU 0x31 +opcode_ld_sp_nnnn EQU 0x31 +opcode_nop_0x00 EQU 0x00 +opcode_nop EQU 0x00 +opcode_or_a_0xb7 EQU 0xb7 +opcode_or_a EQU 0xb7 +opcode_or_b_0xb0 EQU 0xb0 +opcode_or_b EQU 0xb0 +opcode_or_c_0xb1 EQU 0xb1 +opcode_or_c EQU 0xb1 +opcode_or_d_0xb2 EQU 0xb2 +opcode_or_d EQU 0xb2 +opcode_or_e_0xb3 EQU 0xb3 +opcode_or_e EQU 0xb3 +opcode_or_h_0xb4 EQU 0xb4 +opcode_or_h EQU 0xb4 +opcode_or_hl_0xb6 EQU 0xb6 +opcode_or_hl EQU 0xb6 +opcode_or_l_0xb5 EQU 0xb5 +opcode_or_l EQU 0xb5 +opcode_or_nn_0xf6 EQU 0xf6 +opcode_or_nn EQU 0xf6 +opcode_out_nn_a_0xd3 EQU 0xd3 +opcode_out_nn_a EQU 0xd3 +opcode_pop_af_0xf1 EQU 0xf1 +opcode_pop_af EQU 0xf1 +opcode_pop_bc_0xc1 EQU 0xc1 +opcode_pop_bc EQU 0xc1 +opcode_pop_de_0xd1 EQU 0xd1 +opcode_pop_de EQU 0xd1 +opcode_pop_hl_0xe1 EQU 0xe1 +opcode_pop_hl EQU 0xe1 +opcode_push_af_0xf5 EQU 0xf5 +opcode_push_af EQU 0xf5 +opcode_push_bc_0xc5 EQU 0xc5 +opcode_push_bc EQU 0xc5 +opcode_push_de_0xd5 EQU 0xd5 +opcode_push_de EQU 0xd5 +opcode_push_hl_0xe5 EQU 0xe5 +opcode_push_hl EQU 0xe5 +opcode_ret_0xc9 EQU 0xc9 +opcode_ret_c_0xd8 EQU 0xd8 +opcode_ret_c EQU 0xd8 +opcode_ret EQU 0xc9 +opcode_ret_m_0xf8 EQU 0xf8 +opcode_ret_m EQU 0xf8 +opcode_ret_nc_0xd0 EQU 0xd0 +opcode_ret_nc EQU 0xd0 +opcode_ret_nz_0xc0 EQU 0xc0 +opcode_ret_nz EQU 0xc0 +opcode_ret_p_0xf0 EQU 0xf0 +opcode_ret_pe_0xe8 EQU 0xe8 +opcode_ret_pe EQU 0xe8 +opcode_ret_p EQU 0xf0 +opcode_ret_po_0xe0 EQU 0xe0 +opcode_ret_po EQU 0xe0 +opcode_ret_z_0xc8 EQU 0xc8 +opcode_ret_z EQU 0xc8 +opcode_rla_0x17 EQU 0x17 +opcode_rla EQU 0x17 +opcode_rlca_0x07 EQU 0x07 +opcode_rlca EQU 0x07 +opcode_rra_0x1f EQU 0x1f +opcode_rra EQU 0x1f +opcode_rrca_0x0f EQU 0x0f +opcode_rrca EQU 0x0f +opcode_rst_0_0xc7 EQU 0xc7 +opcode_rst_0 EQU 0xc7 +opcode_rst_10h_0xd7 EQU 0xd7 +opcode_rst_10h EQU 0xd7 +opcode_rst_18h_0xdf EQU 0xdf +opcode_rst_18h EQU 0xdf +opcode_rst_20h_0xe7 EQU 0xe7 +opcode_rst_20h EQU 0xe7 +opcode_rst_28h_0xef EQU 0xef +opcode_rst_28h EQU 0xef +opcode_rst_30h_0xf7 EQU 0xf7 +opcode_rst_30h EQU 0xf7 +opcode_rst_38h_0xff EQU 0xff +opcode_rst_38h EQU 0xff +opcode_rst_8h_0xcf EQU 0xcf +opcode_rst_8h EQU 0xcf +opcode_sbc_a_a_0x9f EQU 0x9f +opcode_sbc_a_a EQU 0x9f +opcode_sbc_a_b_0x98 EQU 0x98 +opcode_sbc_a_b EQU 0x98 +opcode_sbc_a_c_0x99 EQU 0x99 +opcode_sbc_a_c EQU 0x99 +opcode_sbc_a_d_0x9a EQU 0x9a +opcode_sbc_a_d EQU 0x9a +opcode_sbc_a_e_0x9b EQU 0x9b +opcode_sbc_a_e EQU 0x9b +opcode_sbc_a_h_0x9c EQU 0x9c +opcode_sbc_a_h EQU 0x9c +opcode_sbc_a_hl_0x9e EQU 0x9e +opcode_sbc_a_hl EQU 0x9e +opcode_sbc_a_l_0x9d EQU 0x9d +opcode_sbc_a_l EQU 0x9d +opcode_sbc_a_nn_0xde EQU 0xde +opcode_sbc_a_nn EQU 0xde +opcode_scf_0x37 EQU 0x37 +opcode_scf EQU 0x37 +opcode_sub_a_0x97 EQU 0x97 +opcode_sub_a EQU 0x97 +opcode_sub_b_0x90 EQU 0x90 +opcode_sub_b EQU 0x90 +opcode_sub_c_0x91 EQU 0x91 +opcode_sub_c EQU 0x91 +opcode_sub_d_0x92 EQU 0x92 +opcode_sub_d EQU 0x92 +opcode_sub_e_0x93 EQU 0x93 +opcode_sub_e EQU 0x93 +opcode_sub_h_0x94 EQU 0x94 +opcode_sub_h EQU 0x94 +opcode_sub_hl_0x96 EQU 0x96 +opcode_sub_hl EQU 0x96 +opcode_sub_l_0x95 EQU 0x95 +opcode_sub_l EQU 0x95 +opcode_sub_nn_0xd6 EQU 0xd6 +opcode_sub_nn EQU 0xd6 +opcode_xor_a_0xaf EQU 0xaf +opcode_xor_a EQU 0xaf +opcode_xor_b_0xa8 EQU 0xa8 +opcode_xor_b EQU 0xa8 +opcode_xor_c_0xa9 EQU 0xa9 +opcode_xor_c EQU 0xa9 +opcode_xor_d_0xaa EQU 0xaa +opcode_xor_d EQU 0xaa +opcode_xor_e_0xab EQU 0xab +opcode_xor_e EQU 0xab +opcode_xor_h_0xac EQU 0xac +opcode_xor_h EQU 0xac +opcode_xor_hl_0xae EQU 0xae +opcode_xor_hl EQU 0xae +opcode_xor_l_0xad EQU 0xad +opcode_xor_l EQU 0xad +opcode_xor_nn_0xee EQU 0xee +opcode_xor_nn EQU 0xee + diff --git a/tools/rasm/win32.bat b/tools/rasm/win32.bat new file mode 100755 index 0000000..f73cca4 --- /dev/null +++ b/tools/rasm/win32.bat @@ -0,0 +1,7 @@ +cl ZX0-main\src\compress.c /Ox /c -I ZX0-main\src +cl ZX0-main\src\optimize.c /Ox /c -I ZX0-main\src +cl ZX0-main\src\memory.c /Ox /c -I ZX0-main\src + +cl rasm.c /Ox /DNOAPULTRA=1 /DDOS_WIN=1 optimize.obj compress.obj memory.obj + + diff --git a/tools/rasm/zx7.h b/tools/rasm/zx7.h index f03659d..f371e58 100644 --- a/tools/rasm/zx7.h +++ b/tools/rasm/zx7.h @@ -46,9 +46,9 @@ typedef struct optimal_t { int len; } Optimal; -Optimal *optimize(unsigned char *input_data, size_t input_size); +Optimal *zx7_optimize(unsigned char *input_data, int input_size); -unsigned char *ZX7_compress(Optimal *optimal, unsigned char *input_data, size_t input_size, size_t *output_size); +unsigned char *ZX7_compress(Optimal *optimal, unsigned char *input_data, int input_size, int *output_size); /* * (c) Copyright 2012 by Einar Saukas. All rights reserved. @@ -75,7 +75,7 @@ unsigned char *ZX7_compress(Optimal *optimal, unsigned char *input_data, size_t * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -int elias_gamma_bits(int value) { +int zx7_elias_gamma_bits(int value) { int bits; bits = 1; @@ -87,10 +87,10 @@ int elias_gamma_bits(int value) { } int count_bits(int offset, int len) { - return 1 + (offset > 128 ? 12 : 8) + elias_gamma_bits(len-1); + return 1 + (offset > 128 ? 12 : 8) + zx7_elias_gamma_bits(len-1); } -Optimal* optimize(unsigned char *input_data, size_t input_size) { +Optimal* zx7_optimize(unsigned char *input_data, int input_size) { size_t *min; size_t *max; Match *matches; @@ -190,20 +190,20 @@ Optimal* optimize(unsigned char *input_data, size_t input_size) { * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -unsigned char* output_data; -size_t output_index; -size_t bit_index; -int bit_mask; +extern unsigned char* output_data; +extern int output_index; +extern int bit_index; +extern int bit_mask; -void write_byte(int value) { +void zx7_write_byte(int value) { output_data[output_index++] = value; } -void write_bit(int value) { +void zx7_write_bit(int value) { if (bit_mask == 0) { bit_mask = 128; bit_index = output_index; - write_byte(0); + zx7_write_byte(0); } if (value > 0) { output_data[bit_index] |= bit_mask; @@ -211,18 +211,18 @@ void write_bit(int value) { bit_mask >>= 1; } -void write_elias_gamma(int value) { +void zx7_write_elias_gamma(int value) { int i; for (i = 2; i <= value; i <<= 1) { - write_bit(0); + zx7_write_bit(0); } while ((i >>= 1) > 0) { - write_bit(value & i); + zx7_write_bit(value & i); } } -unsigned char *ZX7_compress(Optimal *optimal, unsigned char *input_data, size_t input_size, size_t *output_size) { +unsigned char *ZX7_compress(Optimal *optimal, unsigned char *input_data, int input_size, int *output_size) { size_t input_index; size_t input_prev; int offset1; @@ -246,48 +246,48 @@ unsigned char *ZX7_compress(Optimal *optimal, unsigned char *input_data, size_t bit_mask = 0; /* first byte is always literal */ - write_byte(input_data[0]); + zx7_write_byte(input_data[0]); /* process remaining bytes */ while ((input_index = optimal[input_index].bits) > 0) { if (optimal[input_index].len == 0) { /* literal indicator */ - write_bit(0); + zx7_write_bit(0); /* literal value */ - write_byte(input_data[input_index]); + zx7_write_byte(input_data[input_index]); } else { /* sequence indicator */ - write_bit(1); + zx7_write_bit(1); /* sequence length */ - write_elias_gamma(optimal[input_index].len-1); + zx7_write_elias_gamma(optimal[input_index].len-1); /* sequence offset */ offset1 = optimal[input_index].offset-1; if (offset1 < 128) { - write_byte(offset1); + zx7_write_byte(offset1); } else { offset1 -= 128; - write_byte((offset1 & 127) | 128); + zx7_write_byte((offset1 & 127) | 128); for (mask = 1024; mask > 127; mask >>= 1) { - write_bit(offset1 & mask); + zx7_write_bit(offset1 & mask); } } } } /* sequence indicator */ - write_bit(1); + zx7_write_bit(1); /* end marker > MAX_LEN */ for (i = 0; i < 16; i++) { - write_bit(0); + zx7_write_bit(0); } - write_bit(1); + zx7_write_bit(1); return output_data; } -- cgit v1.2.3