From c3b0fa04a663fe233765b83d3be41a42aa08c25d Mon Sep 17 00:00:00 2001 From: "Juan J. Martinez" Date: Mon, 3 May 2021 08:21:10 +0100 Subject: Initial import for public release --- .gitignore | 18 + Makefile | 131 +++ README.md | 46 + cpcfirm.inc | 227 ++++ crt0.s | 55 + font.gif | Bin 0 -> 289 bytes gpl-3.0.txt | 674 +++++++++++ int.h | 100 ++ lib/Makefile | 20 + lib/cpcrslib/GphStrStd.s | 412 +++++++ lib/cpcrslib/LICENSE | 20 + lib/cpcrslib/Makefile | 23 + lib/cpcrslib/Sprites.s | 37 + lib/cpcrslib/TileMap.h | 304 +++++ lib/cpcrslib/Wyz.s | 1403 +++++++++++++++++++++++ lib/cpcrslib/cpc_ClrScr.s | 11 + lib/cpcrslib/cpc_CollSp.s | 126 +++ lib/cpcrslib/cpc_DisableEnableFirmware.s | 28 + lib/cpcrslib/cpc_GetScrAddress.s | 65 ++ lib/cpcrslib/cpc_GetSp.s | 49 + lib/cpcrslib/cpc_GphStr.s | 700 ++++++++++++ lib/cpcrslib/cpc_Keyboard.s | 348 ++++++ lib/cpcrslib/cpc_PrintStr.s | 27 + lib/cpcrslib/cpc_PutMaskSp.s | 79 ++ lib/cpcrslib/cpc_PutMaskSp2x8.s | 45 + lib/cpcrslib/cpc_PutMaskSp4x16.s | 56 + lib/cpcrslib/cpc_PutSp.s | 54 + lib/cpcrslib/cpc_PutSp2x14.s | 50 + lib/cpcrslib/cpc_PutSpTr.s | 75 ++ lib/cpcrslib/cpc_PutSpXOR.s | 79 ++ lib/cpcrslib/cpc_PutSprite.s | 108 ++ lib/cpcrslib/cpc_RLI.s | 39 + lib/cpcrslib/cpc_RRI.s | 39 + lib/cpcrslib/cpc_Random.s | 34 + lib/cpcrslib/cpc_SetBorder.s | 10 + lib/cpcrslib/cpc_SetColour.s | 16 + lib/cpcrslib/cpc_SetInk.s | 12 + lib/cpcrslib/cpc_SetMode.s | 13 + lib/cpcrslib/cpc_SetModo.s | 9 + lib/cpcrslib/cpc_TileMap.s | 1332 ++++++++++++++++++++++ lib/cpcrslib/cpc_UnExoOpt.s | 183 +++ lib/cpcrslib/cpc_Uncrunch.s | 308 +++++ lib/cpcrslib/cpcrslib.h | 116 ++ lib/cpcrslib/cpcwyzlib.h | 18 + lib/cpcrslib/make.bat | 19 + lib/ucl.h | 5 + lib/ucl.s | 360 ++++++ loader.s | 157 +++ loading.png | Bin 0 -> 2336 bytes main.c | 1794 ++++++++++++++++++++++++++++++ menu.png | Bin 0 -> 595 bytes mock.png | Bin 0 -> 2413 bytes music/board.mus | Bin 0 -> 97 bytes music/gameover.mus | Bin 0 -> 121 bytes music/intro.mus | Bin 0 -> 77 bytes music/return.mus | Bin 0 -> 1019 bytes music/theplayer.mus | Bin 0 -> 1215 bytes play.png | Bin 0 -> 787 bytes ship.png | Bin 0 -> 303 bytes sound.c | 40 + sound.h | 36 + splib.c | 325 ++++++ splib.h | 64 ++ tiles-work.png | Bin 0 -> 968 bytes tiles.png | Bin 0 -> 802 bytes tiles_alt.png | Bin 0 -> 562 bytes tools/2CDT/2cdt.cbp | 43 + tools/2CDT/2cdt.depend | 22 + tools/2CDT/2cdt.layout | 7 + tools/2CDT/COPYING | 340 ++++++ tools/2CDT/Makefile | 24 + tools/2CDT/Makefile.win | 33 + tools/2CDT/file_id.diz | 16 + tools/2CDT/readme.txt | 135 +++ tools/2CDT/src/2cdt.c | 1290 +++++++++++++++++++++ tools/2CDT/src/defs.h | 36 + tools/2CDT/src/tzxfile.c | 445 ++++++++ tools/2CDT/src/tzxfile.h | 79 ++ tools/Makefile | 38 + tools/README.ucl | 7 + tools/bin2h.py | 34 + tools/chksize | 42 + tools/dump-pal.py | 95 ++ tools/encrypt.py | 25 + tools/gfx2crtc/AUTHORS | 5 + tools/gfx2crtc/LICENCE | 512 +++++++++ tools/gfx2crtc/LICENSE | 506 +++++++++ tools/gfx2crtc/README | 36 + tools/gfx2crtc/TODO | 9 + tools/gfx2crtc/libraw2crtc.c | 186 ++++ tools/gfx2crtc/libraw2crtc.h | 12 + tools/gfx2crtc/makefile | 29 + tools/gfx2crtc/png2crtc.c | 204 ++++ tools/gfx2crtc/raw2crtc.c | 86 ++ tools/hex2bin-2.0/Makefile | 42 + tools/hex2bin-2.0/bin/.deleteme | 0 tools/hex2bin-2.0/bin/hex2bin | Bin 0 -> 33200 bytes tools/hex2bin-2.0/bin/mot2bin | Bin 0 -> 33200 bytes tools/hex2bin-2.0/doc/CRC list.txt | 542 +++++++++ tools/hex2bin-2.0/doc/ChangeLog_hex2bin | 57 + tools/hex2bin-2.0/doc/ChangeLog_mot2bin | 49 + tools/hex2bin-2.0/doc/README | 225 ++++ tools/hex2bin-2.0/doc/S-record.txt | 361 ++++++ tools/hex2bin-2.0/doc/formats.txt | 72 ++ tools/hex2bin-2.0/doc/intelhex.spc | 409 +++++++ tools/hex2bin-2.0/doc/srec.txt | 447 ++++++++ tools/hex2bin-2.0/src/binary.c | 196 ++++ tools/hex2bin-2.0/src/binary.h | 36 + tools/hex2bin-2.0/src/common.c | 527 +++++++++ tools/hex2bin-2.0/src/common.h | 116 ++ tools/hex2bin-2.0/src/hex2bin.1 | 294 +++++ tools/hex2bin-2.0/src/hex2bin.c | 587 ++++++++++ tools/hex2bin-2.0/src/hex2bin.pod | 161 +++ tools/hex2bin-2.0/src/libcrc.c | 204 ++++ tools/hex2bin-2.0/src/libcrc.h | 44 + tools/hex2bin-2.0/src/mot2bin.c | 518 +++++++++ tools/iDSK/.gitignore | 7 + tools/iDSK/AUTHORS | 3 + tools/iDSK/CMakeLists.txt | 14 + tools/iDSK/COPYING | 1 + tools/iDSK/src/Basic.cpp | 350 ++++++ tools/iDSK/src/Basic.h | 8 + tools/iDSK/src/BitmapCPC.cpp | 264 +++++ tools/iDSK/src/BitmapCPC.h | 46 + tools/iDSK/src/Dams.cpp | 184 +++ tools/iDSK/src/Dams.h | 8 + tools/iDSK/src/Desass.cpp | 532 +++++++++ tools/iDSK/src/Desass.h | 8 + tools/iDSK/src/GestDsk.cpp | 1183 ++++++++++++++++++++ tools/iDSK/src/GestDsk.h | 168 +++ tools/iDSK/src/Main.cpp | 284 +++++ tools/iDSK/src/Main.h | 19 + tools/iDSK/src/MyType.h | 19 + tools/iDSK/src/Outils.cpp | 165 +++ tools/iDSK/src/Outils.h | 19 + tools/iDSK/src/ViewFile.cpp | 36 + tools/iDSK/src/ViewFile.h | 13 + tools/iDSK/src/endianPPC.cpp | 20 + tools/iDSK/src/endianPPC.h | 22 + tools/iDSK/src/getopt_pp.cpp | 307 +++++ tools/iDSK/src/getopt_pp.h | 745 +++++++++++++ tools/img2f.py | 54 + tools/img2sprite.py | 115 ++ tools/map.py | 162 +++ tools/ucl.c | 94 ++ turboload.s | 249 +++++ 146 files changed, 24581 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.md create mode 100644 cpcfirm.inc create mode 100644 crt0.s create mode 100644 font.gif create mode 100644 gpl-3.0.txt create mode 100644 int.h create mode 100644 lib/Makefile create mode 100644 lib/cpcrslib/GphStrStd.s create mode 100644 lib/cpcrslib/LICENSE create mode 100644 lib/cpcrslib/Makefile create mode 100644 lib/cpcrslib/Sprites.s create mode 100644 lib/cpcrslib/TileMap.h create mode 100644 lib/cpcrslib/Wyz.s create mode 100644 lib/cpcrslib/cpc_ClrScr.s create mode 100644 lib/cpcrslib/cpc_CollSp.s create mode 100644 lib/cpcrslib/cpc_DisableEnableFirmware.s create mode 100644 lib/cpcrslib/cpc_GetScrAddress.s create mode 100644 lib/cpcrslib/cpc_GetSp.s create mode 100644 lib/cpcrslib/cpc_GphStr.s create mode 100644 lib/cpcrslib/cpc_Keyboard.s create mode 100644 lib/cpcrslib/cpc_PrintStr.s create mode 100644 lib/cpcrslib/cpc_PutMaskSp.s create mode 100644 lib/cpcrslib/cpc_PutMaskSp2x8.s create mode 100644 lib/cpcrslib/cpc_PutMaskSp4x16.s create mode 100644 lib/cpcrslib/cpc_PutSp.s create mode 100644 lib/cpcrslib/cpc_PutSp2x14.s create mode 100644 lib/cpcrslib/cpc_PutSpTr.s create mode 100644 lib/cpcrslib/cpc_PutSpXOR.s create mode 100644 lib/cpcrslib/cpc_PutSprite.s create mode 100644 lib/cpcrslib/cpc_RLI.s create mode 100644 lib/cpcrslib/cpc_RRI.s create mode 100644 lib/cpcrslib/cpc_Random.s create mode 100644 lib/cpcrslib/cpc_SetBorder.s create mode 100644 lib/cpcrslib/cpc_SetColour.s create mode 100644 lib/cpcrslib/cpc_SetInk.s create mode 100644 lib/cpcrslib/cpc_SetMode.s create mode 100644 lib/cpcrslib/cpc_SetModo.s create mode 100644 lib/cpcrslib/cpc_TileMap.s create mode 100644 lib/cpcrslib/cpc_UnExoOpt.s create mode 100644 lib/cpcrslib/cpc_Uncrunch.s create mode 100644 lib/cpcrslib/cpcrslib.h create mode 100644 lib/cpcrslib/cpcwyzlib.h create mode 100644 lib/cpcrslib/make.bat create mode 100644 lib/ucl.h create mode 100644 lib/ucl.s create mode 100644 loader.s create mode 100644 loading.png create mode 100644 main.c create mode 100644 menu.png create mode 100644 mock.png create mode 100644 music/board.mus create mode 100644 music/gameover.mus create mode 100644 music/intro.mus create mode 100644 music/return.mus create mode 100644 music/theplayer.mus create mode 100644 play.png create mode 100644 ship.png create mode 100644 sound.c create mode 100644 sound.h create mode 100644 splib.c create mode 100644 splib.h create mode 100644 tiles-work.png create mode 100644 tiles.png create mode 100644 tiles_alt.png create mode 100644 tools/2CDT/2cdt.cbp create mode 100644 tools/2CDT/2cdt.depend create mode 100644 tools/2CDT/2cdt.layout create mode 100644 tools/2CDT/COPYING create mode 100644 tools/2CDT/Makefile create mode 100644 tools/2CDT/Makefile.win create mode 100644 tools/2CDT/file_id.diz create mode 100644 tools/2CDT/readme.txt create mode 100644 tools/2CDT/src/2cdt.c create mode 100644 tools/2CDT/src/defs.h create mode 100644 tools/2CDT/src/tzxfile.c create mode 100644 tools/2CDT/src/tzxfile.h create mode 100644 tools/Makefile create mode 100644 tools/README.ucl create mode 100755 tools/bin2h.py create mode 100755 tools/chksize create mode 100755 tools/dump-pal.py create mode 100644 tools/encrypt.py create mode 100644 tools/gfx2crtc/AUTHORS create mode 100644 tools/gfx2crtc/LICENCE create mode 100644 tools/gfx2crtc/LICENSE create mode 100644 tools/gfx2crtc/README create mode 100644 tools/gfx2crtc/TODO create mode 100644 tools/gfx2crtc/libraw2crtc.c create mode 100644 tools/gfx2crtc/libraw2crtc.h create mode 100644 tools/gfx2crtc/makefile create mode 100644 tools/gfx2crtc/png2crtc.c create mode 100644 tools/gfx2crtc/raw2crtc.c create mode 100755 tools/hex2bin-2.0/Makefile create mode 100644 tools/hex2bin-2.0/bin/.deleteme create mode 100755 tools/hex2bin-2.0/bin/hex2bin create mode 100755 tools/hex2bin-2.0/bin/mot2bin create mode 100644 tools/hex2bin-2.0/doc/CRC list.txt create mode 100644 tools/hex2bin-2.0/doc/ChangeLog_hex2bin create mode 100644 tools/hex2bin-2.0/doc/ChangeLog_mot2bin create mode 100644 tools/hex2bin-2.0/doc/README create mode 100644 tools/hex2bin-2.0/doc/S-record.txt create mode 100644 tools/hex2bin-2.0/doc/formats.txt create mode 100644 tools/hex2bin-2.0/doc/intelhex.spc create mode 100644 tools/hex2bin-2.0/doc/srec.txt create mode 100644 tools/hex2bin-2.0/src/binary.c create mode 100644 tools/hex2bin-2.0/src/binary.h create mode 100644 tools/hex2bin-2.0/src/common.c create mode 100644 tools/hex2bin-2.0/src/common.h create mode 100644 tools/hex2bin-2.0/src/hex2bin.1 create mode 100644 tools/hex2bin-2.0/src/hex2bin.c create mode 100644 tools/hex2bin-2.0/src/hex2bin.pod create mode 100644 tools/hex2bin-2.0/src/libcrc.c create mode 100644 tools/hex2bin-2.0/src/libcrc.h create mode 100644 tools/hex2bin-2.0/src/mot2bin.c create mode 100644 tools/iDSK/.gitignore create mode 100644 tools/iDSK/AUTHORS create mode 100644 tools/iDSK/CMakeLists.txt create mode 100644 tools/iDSK/COPYING create mode 100644 tools/iDSK/src/Basic.cpp create mode 100644 tools/iDSK/src/Basic.h create mode 100644 tools/iDSK/src/BitmapCPC.cpp create mode 100644 tools/iDSK/src/BitmapCPC.h create mode 100644 tools/iDSK/src/Dams.cpp create mode 100644 tools/iDSK/src/Dams.h create mode 100644 tools/iDSK/src/Desass.cpp create mode 100644 tools/iDSK/src/Desass.h create mode 100644 tools/iDSK/src/GestDsk.cpp create mode 100644 tools/iDSK/src/GestDsk.h create mode 100644 tools/iDSK/src/Main.cpp create mode 100644 tools/iDSK/src/Main.h create mode 100644 tools/iDSK/src/MyType.h create mode 100644 tools/iDSK/src/Outils.cpp create mode 100644 tools/iDSK/src/Outils.h create mode 100644 tools/iDSK/src/ViewFile.cpp create mode 100644 tools/iDSK/src/ViewFile.h create mode 100644 tools/iDSK/src/endianPPC.cpp create mode 100644 tools/iDSK/src/endianPPC.h create mode 100644 tools/iDSK/src/getopt_pp.cpp create mode 100644 tools/iDSK/src/getopt_pp.h create mode 100755 tools/img2f.py create mode 100755 tools/img2sprite.py create mode 100755 tools/map.py create mode 100644 tools/ucl.c create mode 100644 turboload.s diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4b55f63 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +*.o +*.swp +*~ +*.def +*.bin +*.map +*.cdt +*.dsk +*.scr +*.opt +*.rel +*.lk +*.noi +*.lst +*.sym +*.asm +*.ihx + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e45ac61 --- /dev/null +++ b/Makefile @@ -0,0 +1,131 @@ +TARGET=traxtor +GENERATED=font.h menubg.h tiles.h tiles_alt.h playbg.h ship.h return_mus.h board_mus.h gameover_mus.h + +LOADER_ADDR=512 +TMP_ADDR=3072 +APP_ADDR=8072 + +LOADER_ADDR_HEX=$(shell printf "%x" $(LOADER_ADDR)) +TMP_ADDR_HEX=$(shell printf "%x" $(TMP_ADDR)) +APP_ADDR_HEX=$(shell printf "%x" $(APP_ADDR)) + +CC=sdcc +AS=sdasz80 +AR=sdcclib +CFLAGS=-mz80 -Ilib +LDFLAGS=-Llib -L. --data-loc 0 --no-std-crt0 --fomit-frame-pointer + +export PATH:=tools:$(PATH) + +all: + make -C tools + make -C lib + make $(TARGET).dsk + make $(TARGET).cdt + @chksize 8072 main.map + +$(TARGET).dsk: main.bin loader.bin loading.bin + cp loader_disk.bin $(TARGET) + idsk $@ -n -t 1 -i $(TARGET) -e $(LOADER_ADDR_HEX) -c $(LOADER_ADDR_HEX) > /dev/null + rm -f $(TARGET) + cp loading.bin main.bi0 + idsk $@ -t 1 -i main.bi0 -c $(TMP_ADDR_HEX) -s > /dev/null + rm -f main.bi0 + cp main.bin main.bi1 + idsk $@ -t 1 -i main.bi1 -e $(shell awk ' /_main_init/ { print $$1 } ' main.map) -c $(APP_ADDR_HEX) -s > /dev/null + rm -f main.bi1 + +$(TARGET).cdt: main.bin loader.bin loading.bin + 2cdt -n -X $(LOADER_ADDR) -L $(LOADER_ADDR) -r $(TARGET) loader.bin $@ > /dev/null + 2cdt -m 2 loading.bin $@ > /dev/null + 2cdt -m 2 $< $@ > /dev/null + +loader.bin: loader.s turboload.s main.map loading.bin + echo "DISK = 1" > loader.opt + echo "APP_EP = 0x$(shell awk ' /_main_init/ { print $$1 } ' main.map)" >> loader.opt + echo "TMP_ADDR = 0x$(TMP_ADDR_HEX)" >> loader.opt + echo "SCRX_SIZE = $(shell stat -c '%s' loading.bin)" >> loader.opt + echo "APP_ADDR = 0x$(APP_ADDR_HEX)" >> loader.opt + echo "APP_SIZE = $(shell stat -c '%s' main.bin)" >> loader.opt + $(AS) -g -o $< + $(CC) $(CFLAGS) $(LDFLAGS) --code-loc $(LOADER_ADDR) -lucl loader.rel + hex2bin -p 00 loader.ihx + echo "DISK = 0" > loader.opt + echo "APP_EP = 0x$(shell awk ' /_main_init/ { print $$1 } ' main.map)" >> loader.opt + echo "TMP_ADDR = 0x$(TMP_ADDR_HEX)" >> loader.opt + echo "SCRX_SIZE = $(shell stat -c '%s' loading.bin)" >> loader.opt + echo "APP_ADDR = 0x$(APP_ADDR_HEX)" >> loader.opt + echo "APP_SIZE = $(shell stat -c '%s' main.bin)" >> loader.opt + $(AS) -g -o $< + $(CC) $(CFLAGS) $(LDFLAGS) --code-loc $(LOADER_ADDR) -lucl -o loader_disk.ihx loader.rel + hex2bin -p 00 loader_disk.ihx + +loading.bin: loading.png + png2crtc loading.png loading.scr 7 1 + dump-pal.py loading.png pal.bin + echo -n "SCRX" > loading.bin + cat pal.bin >> loading.bin + ucl < loading.scr >> loading.bin + +main.bin: main.c crt0.s splib.lib sound.h sound.rel $(GENERATED) + rm -f main.map + $(AS) -g -o crt0.s + $(CC) $(CFLAGS) $(LDFLAGS) -lsplib -lucl -lcpcrslib -lcpcwyzlib --code-loc $(APP_ADDR) crt0.rel sound.rel $< + hex2bin -p 00 main.ihx + +splib.lib: splib.c splib.h + $(CC) $(CFLAGS) $(LDFLAGS) -c $< + $(AR) -a $@ splib.rel + +font.h: font.gif + img2f.py --effect font.gif font > font.h + +menubg.h: menu.png + img2sprite.py --height 56 --width 160 -b menu.png > menubg.bin + ucl < menubg.bin > menu.bin + bin2h.py menu.bin menubg > menubg.h + +tiles.h: tiles.png + img2sprite.py --height 9 --width 12 -i tiles tiles.png > tiles.h + +tiles_alt.h: tiles_alt.png + img2sprite.py --height 9 --width 12 -i tiles_alt tiles_alt.png > tiles_alt.h + +ship.h: ship.png + img2sprite.py --height 21 --width 12 -i ship ship.png > ship.h + +playbg.h: play.png + png2crtc play.png play.scr 7 0 + ucl < play.scr > play.bin + bin2h.py play.bin playbg > playbg.h + +sound.rel: sound.c sound.h theplayer_mus.h intro_mus.h + $(CC) $(CFLAGS) $(LDFLAGS) -c $< + +return_mus.h: music/return.mus + ucl < music/return.mus > return.bin + bin2h.py return.bin return_mus > return_mus.h + +board_mus.h: music/board.mus + ucl < music/board.mus > board.bin + bin2h.py board.bin board_mus > board_mus.h + +gameover_mus.h: music/gameover.mus + ucl < music/gameover.mus > gameover.bin + bin2h.py gameover.bin gameover_mus > gameover_mus.h + +theplayer_mus.h: music/theplayer.mus + bin2h.py music/theplayer.mus theplayer_mus > theplayer_mus.h + +intro_mus.h: music/intro.mus + bin2h.py music/intro.mus intro_mus > intro_mus.h + +.PHONY: clean all cleanall +clean: + rm -f *.dsk *.bin *.cdt *.scr *.rel *.opt *.lk *.noi *.map *.lst *.sym *.asm *.ihx *.lib $(GENERATED) theplayer_mus.h intro_mus.h + +cleanall: + make clean + make -C tools clean + make -C lib clean + diff --git a/README.md b/README.md new file mode 100644 index 0000000..7fd887e --- /dev/null +++ b/README.md @@ -0,0 +1,46 @@ +# The Return of Traxtor (CPC) + +This is the source code of [The Return of Traxtor](https://www.usebox.net/jjm/return-of-traxtor-cpc/) for the Amstrad CPC. + +I'm sharing it as an historic curiosity and hoping that it may be interesting, +without any support! + +It includes my first tiles/sprites engine for the CPC (see `splib.c`), although +this game is only using tiles. + +Some of the dependencies are old and likely to have bugs that have been fixed +in later relases, so you shouldn't use the versions that are provided here for +any new projects. This is how the game was built in 2015! + +You will need: + +- A POSIX environment (Linux is perfect, Debian recommended) +- GCC, GNU Make, cmake, Python 2 and 3, PIL (or Pillow) for Python, libpng and + libucl for development +- SDCC 3.5; later versions may not work as SDCC has changed the tool that + manages libraries! + +Once all dependencies are met, run `make`. + +It should end with something like this: +``` +*WARNING* Initialized data found +*** + Max: 41080 bytes + Current: 24393 bytes (16687 bytes left) +*** +``` + +At this point `traxtor.cdt` and `traxtor.dsk` should be ready to load in your +emulator. + +## License + +The source code of the game is licensed GPL 3.0, the assets are [CC-BY-SA](https://creativecommons.org/licenses/by-sa/2.0/). + +The tools/libraries included that I don't own have their own copyright notices +and license (some are public domain, others are open source). + +The loading screen is based on the original made by Craig Stevenson for the ZX +Spectrum. + diff --git a/cpcfirm.inc b/cpcfirm.inc new file mode 100644 index 0000000..88a9f1f --- /dev/null +++ b/cpcfirm.inc @@ -0,0 +1,227 @@ +kl_probe_rom = 0xb915 +kl_choke_off = 0xbcc8 +kl_rom_walk = 0xbccb +kl_init_back = 0xbcce +kl_log_ext = 0xbcd1 +kl_find_command = 0xbcd4 +kl_new_framefly = 0xbcd7 +kl_add_framefly = 0xbcda +kl_del_framefly = 0xbcdd +kl_new_fast_ticker = 0xbce0 +kl_add_fast_ticker = 0xbce3 +kl_del_fast_ticker = 0xbce6 +kl_add_ticker = 0xbce9 +kl_del_ticker = 0xbcec +kl_init_event = 0xbcef +kl_event = 0xbcf2 +kl_sync_reset = 0xbcf5 +kl_del_synchronous = 0xbcf8 +kl_next_sync = 0xbcfb +kl_do_sync = 0xbcfe +kl_done_sync = 0xbd01 +kl_event_disable = 0xbd04 +kl_event_enable = 0xbd07 +kl_disarm_event = 0xbd0a +kl_time_please = 0xbd0d +kl_time_set = 0xbd10 + +km_initialise = 0xbb00 +km_reset = 0xbb03 +km_wait_char = 0xbb06 +km_read_char = 0xbb09 +km_char_return = 0xbb0c +km_set_expand = 0xbb0f +km_get_expand = 0xbb12 +km_exp_buffer = 0xbb15 +km_wait_key = 0xbb18 +km_read_key = 0xbb1b +km_test_key = 0xbb1e +km_get_state = 0xbb21 +km_get_joystick = 0xbb24 +km_set_translate = 0xbb27 +km_get_translate = 0xbb2a +km_set_shift = 0xbb2d +km_get_shift = 0xbb30 +km_set_control = 0xbb33 +km_get_control = 0xbb36 +km_set_repeat = 0xbb39 +km_get_repeat = 0xbb3c +km_set_delay = 0xbb3f +km_get_delay = 0xbb42 +km_arm_break = 0xbb45 +km_disarm_break = 0xbb48 +km_break_event = 0xbb4b + +txt_initialise = 0xbb4e +txt_reset = 0xbb51 +txt_vdu_enable = 0xbb54 +txt_vdu_disable = 0xbb57 +txt_output = 0xbb5a +txt_wr_char = 0xbb5d +txt_rd_char = 0xbb60 +txt_set_graphic = 0xbb63 +txt_win_enable = 0xbb66 +txt_get_window = 0xbb69 +txt_clear_window = 0xbb6c +txt_set_column = 0xbb6f +txt_set_row = 0xbb72 +txt_set_cursor = 0xbb75 +txt_get_cursor = 0xbb78 +txt_cur_enable = 0xbb7b +txt_cur_disable = 0xbb7e +txt_cur_on = 0xbb81 +txt_cur_off = 0xbb84 +txt_validate = 0xbb87 +txt_place_cursor = 0xbb8a +txt_remove_cursor = 0xbb8d +txt_set_pen = 0xbb90 +txt_get_pen = 0xbb93 +txt_set_paper = 0xbb96 +txt_get_paper = 0xbb99 +txt_inverse = 0xbb9c +txt_set_back = 0xbb9f +txt_get_back = 0xbba2 +txt_get_matrix = 0xbba5 +txt_set_matrix = 0xbba8 +txt_set_m_table = 0xbbab +txt_get_m_table = 0xbbae +txt_get_controls = 0xbbb1 +txt_str_select = 0xbbb4 +txt_swap_streams = 0xbbb7 + +gra_initialise = 0xbbba +gra_reset = 0xbbbd +gra_move_absolute = 0xbbc0 +gra_move_relative = 0xbbc3 +gra_ask_cursor = 0xbbc6 +gra_set_origin = 0xbbc9 +gra_get_origin = 0xbbcc +gra_win_width = 0xbbcf +gra_win_height = 0xbbd2 +gra_get_w_width = 0xbbd5 +gra_get_w_height = 0xbbd8 +gra_clear_window = 0xbbdb +gra_set_pen = 0xbbde +gra_get_pen = 0xbbe1 +gra_set_paper = 0xbbe4 +gra_get_paper = 0xbbe7 +gra_plot_absolute = 0xbbea +gra_plot_relative = 0xbbed +gra_test_absolute = 0xbbf0 +gra_test_relative = 0xbbf3 +gra_line_absolute = 0xbbf6 +gra_line_relative = 0xbbf9 +gra_wr_char = 0xbbfc + + +scr_initialise = 0xbbff +scr_reset = 0xbc02 +scr_set_offset = 0xbc05 +scr_set_base = 0xbc08 +scr_get_location = 0xbc0b +scr_set_mode = 0xbc0e +scr_get_mode = 0xbc11 +scr_clear = 0xbc14 +scr_char_limits = 0xbc17 +scr_char_position = 0xbc1a +scr_dot_position = 0xbc1d +scr_next_byte = 0xbc20 +scr_prev_byte = 0xbc23 +scr_next_line = 0xbc26 +scr_prev_line = 0xbc29 +scr_ink_encode = 0xbc2c +scr_ink_decode = 0xbc2f +scr_set_ink = 0xbc32 +scr_get_ink = 0xbc35 +scr_set_border = 0xbc38 +scr_get_border = 0xbc3b +scr_set_flashing = 0xbc3e +scr_get_flashing = 0xbc41 +scr_fill_box = 0xbc44 +scr_flood_box = 0xbc17 +scr_char_invert = 0xbc4a +scr_hw_roll = 0xbc4d +scr_sw_roll = 0xbc50 +scr_unpack = 0xbc53 +scr_repack = 0xbc56 +scr_access = 0xbc59 +scr_pixels = 0xbc5c +scr_horizontal = 0xbc5f +scr_vertical = 0xbc62 + + +cas_initialise = 0xbc65 +cas_set_speed = 0xbc68 +cas_noisy = 0xbc6b +cas_start_motor = 0xbc6e +cas_stop_motor = 0xbc71 +cas_restore_motor = 0xbc74 +cas_in_open = 0xbc77 +cas_in_close = 0xbc7a +cas_in_abandon = 0xbc7d +cas_in_char = 0xbc80 +cas_in_direct = 0xbc83 +cas_return = 0xbc86 +cas_test_eof = 0xbc89 +cas_out_open = 0xbc8c +cas_out_close = 0xbc8f +cas_out_abandon = 0xbc92 +cas_out_char = 0xbc95 +cas_out_direct = 0xbc98 +cas_catalog = 0xbc9b +cas_write = 0xbc9e +cas_read = 0xbca1 +cas_check = 0xbca4 + +sound_reset = 0xbca7 +sound_queue = 0xbcaa +sound_check = 0xbcad +sound_arm_event = 0xbcb0 +sound_release = 0xbcb3 +sound_hold = 0xbcb6 +sound_continue = 0xbcb9 +sound_ampl_envelope = 0xbcbc +sound_tone_envelope = 0xbcbf +sound_a_address = 0xbcc2 +sound_t_address = 0xbcc5 + + +mc_boot_program = 0xbd13 +mc_start_program = 0xbd16 +mc_wait_flyback = 0xbd19 +mc_set_mode = 0xbd1c +mc_screen_offset = 0xbd1f +mc_clear_inks = 0xbd22 +mc_set_inks = 0xbd25 +mc_reset_printer = 0xbd28 +mc_print_char = 0xbd2b +mc_busy_printer = 0xbd2e +mc_send_printer = 0xbd31 +mc_sound_register = 0xbd34 +mc_jump_restore = 0xbd37 + +bios_set_message = 0xc033 +bios_setup_disc = 0xc036 +bios_select_format = 0xc039 +bios_read_sector = 0xc03c +bios_write_sector = 0xc03f +bios_format_track = 0xc042 +bios_move_track = 0xc045 +bios_get_status = 0xc048 +bios_set_retry_count = 0xc04b +bios_get_sector_data = 0xc56c + +; 664 + 6128 only +km_set_locks = 0xbd3a +km_flush = 0xbd3d +txt_ask_state = 0xbd40 +gra_default = 0xbd43 +gra_set_back = 0xbd46 +gra_set_first = 0xbd49 +gra_set_line_mask = 0xbd4c +gra_from_user = 0xbd4f +gra_fill = 0xbd52 +scr_set_position = 0xbd55 +mc_print_translation = 0xbd58 +kl_bank_switch = 0xbd5b ; 6128 only + diff --git a/crt0.s b/crt0.s new file mode 100644 index 0000000..37c5fae --- /dev/null +++ b/crt0.s @@ -0,0 +1,55 @@ +.module crt0 +.globl _main +.globl _main_init + + .area _HOME + .area _CODE + .area _INITIALIZER + .area _GSINIT + .area _GSFINAL + + .area _DATA + .area _INITIALIZED + .area _BSEG + .area _BSS + .area _HEAP + + .area _CODE + +_main_init:: + + di + ; disable the firmware + ld hl, #0x38 + ld (hl), #0xfb + inc hl + ld (hl), #0xc9 + + ; disable upper/lower roms + ld bc, #0x7f8c + out (c), c + + ; put the stack as high as we can + ld sp, #0xc000 + ei + + call gsinit + call _main + +halt0: + halt + jr halt0 + + .area _GSINIT +gsinit:: + ld bc, #l__INITIALIZER + ld a, b + or a, c + jr Z, gsinit_next + ld de, #s__INITIALIZED + ld hl, #s__INITIALIZER + ldir +gsinit_next: + +.area _GSFINAL + ret diff --git a/font.gif b/font.gif new file mode 100644 index 0000000..b972271 Binary files /dev/null and b/font.gif differ diff --git a/gpl-3.0.txt b/gpl-3.0.txt new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/gpl-3.0.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/int.h b/int.h new file mode 100644 index 0000000..3932071 --- /dev/null +++ b/int.h @@ -0,0 +1,100 @@ +/* + The Return of Traxtor (Amstrad CPC) + Copyright (C) 2015 Juan J. Martinez + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ +#ifndef _INT_H +#define _INT_H + +#ifndef WFRAMES +#define WFRAMES 4 +#endif + +// timer +unsigned char tick; +unsigned char timer; +unsigned char playerISR; + +void +wait() +{ + while ((unsigned char)(tick - timer) < WFRAMES) + __asm__("halt"); + timer = tick; +} + +void +WyzPlayerOn() +{ + __asm; + di + ld a, #1 + ld (_playerISR), a + ei + __endasm; +} + +void +WyzPlayerOff() +{ + __asm; + di + xor a + ld (_playerISR), a + call _cpc_WyzSetPlayerOff + ei + __endasm; + +} + +void +setup_int() +{ + tick = 0; + timer = 0; + playerISR = 0; + __asm; + di + + ld ix, #0x0038 + ld hl, #isr + ld (ix), #0xc3 + ld 1(ix), l + ld 2(ix), h + im 1 + + ei + jp setup_done + + isr: + push af + ld a, (#_tick) + inc a + ld (#_tick), a + ld a, (#_playerISR) + or a + jp z, player_is_off + + jp _cpc_WyzPlayerISR + player_is_off: + pop af + ei + ret + + setup_done: + __endasm; +} + +#endif // _INT_H diff --git a/lib/Makefile b/lib/Makefile new file mode 100644 index 0000000..a0c7d41 --- /dev/null +++ b/lib/Makefile @@ -0,0 +1,20 @@ +all: ucl.lib cpcrslib.lib + +AS=sdasz80 +AR=sdcclib + +ucl.lib: ucl.s + $(AS) -o $< + $(AR) -a $@ ucl.rel + +cpcrslib.lib: $(wildcard cpcrslib/*.s) + make -C cpcrslib + +cpcwyzlib.lib: $(wildcard cpcrslib/*.s) + make -C cpcwyzlib + +.PHONY: clean +clean: + rm -f *.rel *.lib + make -C cpcrslib clean + diff --git a/lib/cpcrslib/GphStrStd.s b/lib/cpcrslib/GphStrStd.s new file mode 100644 index 0000000..08c19ec --- /dev/null +++ b/lib/cpcrslib/GphStrStd.s @@ -0,0 +1,412 @@ +; ****************************************************** +; ** Librera de rutinas SDCC para Amstrad CPC ** +; ** Ral Simarro (Artaburu) - 2009, 2012 ** +; ****************************************************** + +cpc_GetScrAddress0: ;en HL estn las coordenadas + + ;LD A,H + LD (#inc_ancho+1),A + LD A,L + SRL A + SRL A + SRL A + ; A indica el bloque a multiplicar x &50 + LD D,A ;D + SLA A + SLA A + SLA A + SUB L + NEG + ; A indica el desplazamiento a multiplicar x &800 + LD E,A ;E + LD L,D + LD H,#0 + ADD HL,HL + LD BC,#bloques + ADD HL,BC + ;HL APUNTA AL BLOQUE BUSCADO + LD C,(HL) + INC HL + LD H,(HL) + LD L,C + ;HL TIENE EL VALOR DEL BLOQUE DE 8 BUSCADO + PUSH HL + LD D,#0 + LD HL,#sub_bloques + ADD HL,DE + LD A,(HL) + POP HL + ADD H + LD H,A +inc_ancho: + LD E,#0 + ADD HL,DE + RET + +bloques: +.DW #0XC000,#0XC050,#0XC0A0,#0XC0F0,#0XC140,#0XC190,#0XC1E0,#0XC230,#0XC280,#0XC2D0,#0XC320,#0XC370,#0XC3C0,#0XC410,#0XC460,#0XC4B0,#0XC500,#0XC550,#0XC5A0,#0XC5F0,#0XC640,#0XC690,#0XC6E0,#0XC730,#0XC780 +sub_bloques: +.DB #0X00,#0X08,#0X10,#0X18,#0X20,#0X28,#0X30,#0X38 + + + + +.globl _cpc_PrintGphStrStd + +_cpc_PrintGphStrStd:: + ld ix,#2 + add ix,sp + ld l,3 (ix) + ld h,4 (ix) ;destino + ld e,1 (ix) + ld d,2 (ix) ;texto origen + ld a,0 (ix) ;color + ld (#color_uso+1),a + JP cpc_PrintGphStrStd0 + + +.globl _cpc_PrintGphStrStdXY + +_cpc_PrintGphStrStdXY:: +;preparacin datos impresin. El ancho y alto son fijos! + ld ix,#2 + add ix,sp + ld L,4 (ix) + ld A,3 (ix) ;pantalla + call cpc_GetScrAddress0 + ld e,1 (ix) + ld d,2 (ix) ;texto origen + ld a,0 (ix) ;color + ld (#color_uso+1),a + JP cpc_PrintGphStrStd0 + +color0: + XOR A + CALL metecolor + JP sigue +color1: + LD A,#0B00001000 + CALL metecolor + JP sigue +color2: + LD A,#0B10000000 + CALL metecolor + JP sigue +color3: + LD A,#0b10001000 + CALL metecolor + JP sigue +metecolor: + LD (#cc0_gpstd-1),A + LD (#cc4_gpstd-1),A + SRL A + LD (#cc1_gpstd-1),A + LD (#cc5_gpstd-1),A + SRL A + LD (#cc2_gpstd-1),A + LD (#cc6_gpstd-1),A + SRL A + LD (#cc3_gpstd-1),A + LD (#cc7_gpstd-1),A + RET + +cpc_PrintGphStrStd0: +;; marcar el color con que se imprime +color_uso: + LD A,#1 + OR A + JP Z,color0 + CP #1 + JP Z,color1 + CP #2 + JP Z,color2 + CP #3 + JP Z,color3 +sigue: + + ;trabajo previo: Para tener una lista de trabajos de impresin. No se interrumpe + ;la impresin en curso. + LD A,(#imprimiendo) + CP #1 + JP Z,add_elemento + LD (#direcc_destino),HL + EX DE,HL + CALL bucle_texto0 + +;antes de terminar, se mira si hay algo en cola. +bucle_cola_impresion: + LD A,(#elementos_cola) + OR A + JP Z,terminar_impresion + CALL leer_elemento + JP bucle_cola_impresion + +terminar_impresion: + XOR A + LD (#imprimiendo),A + RET +entrar_cola_impresion: + ;si se est imprimiendo se mete el valor en la cola + RET +add_elemento: + DI + LD IX,(#pos_cola) + LD 0 (IX),L + LD 1 (IX),H + LD 2 (IX),E + LD 3 (IX),D + INC IX + INC IX + INC IX + INC IX + Ld (#pos_cola),IX + LD HL,#elementos_cola + INC (HL) + EI + RET +leer_elemento: + DI + LD IX,(#pos_cola) + LD L,0 (IX) + LD H,1 (IX) + LD E,2 (IX) + LD D,3 (IX) + DEC IX + DEC IX + DEC IX + DEC IX + LD (#pos_cola),IX + LD HL,#elementos_cola + DEC (HL) + EI + RET + +elementos_cola: + .DW #0 +pos_cola: + .DW cola_impresion +cola_impresion: + .DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 ; defs 12 +bucle_texto0: + LD A,#1 + LD (#imprimiendo),A + LD A,(#first_char8) + LD B,A ;resto 48 para saber el nmero del caracter (En ASCII 0=48) + LD A,(HL) + OR A ;CP 0 + RET Z + SUB B + LD BC,#cpc_Chars8 ;apunto a la primera letra + PUSH HL + LD L,A + LD H,#0 + ADD HL,HL + ADD HL,HL + ADD HL,HL + ADD HL,BC + CALL escribe_letra_gpstd + LD HL,(#direcc_destino) + + LD DE,#letra_decodificada + CALL cpc_PutSp0_gpstd + LD HL,(#direcc_destino) + INC HL + INC HL + LD (#direcc_destino),HL + POP HL + INC HL + JP bucle_texto0 + +imprimiendo: + .db #0 +direcc_destino: + .dw #0 + + +cpc_PutSp0_gpstd: + .DB #0XFD + LD H,#8 + LD B,#7 + LD C,B +loop_alto_2_gpstd: +loop_ancho_2_gpstd: + EX DE,HL + LDI + LDI + .DB #0XFD + DEC H + RET Z + EX DE,HL +salto_linea_gpstd: + LD C,#0XFE + ADD HL,BC + JP NC,loop_alto_2_gpstd + LD BC,#0XC050 + ADD HL,BC + LD B,#7 + JP loop_alto_2_gpstd + + + +escribe_letra_gpstd: ;; lee el byte y lo interpreta + LD IY,#letra_decodificada + LD B,#8 +bucle_alto_gpstd: + PUSH BC ;leo el byte... ahora se miran sus bits y se rellena el caracter a imprimir + XOR A + LD B,(HL) + BIT 7,B + JP Z,cc0_gpstd + OR #0b10001000 +cc0_gpstd: + BIT 6,B + JP Z,cc1_gpstd + OR #0b01000100 +cc1_gpstd: + BIT 5,B + JP Z,cc2_gpstd + OR #0b00100010 +cc2_gpstd: + BIT 4,B + JP Z,cc3_gpstd + OR #0b00010001 +cc3_gpstd: + ;primer byte + LD 0 (IY),A + INC IY + XOR A + BIT 3,B + JP Z,cc4_gpstd + OR #0b10001000 +cc4_gpstd: + BIT 2,B + JP Z,cc5_gpstd + OR #0b01000100 +cc5_gpstd: + BIT 1,B + JP Z,cc6_gpstd + OR #0b00100010 +cc6_gpstd: + BIT 0,B + JP Z,cc7_gpstd + OR #0b00010001 +cc7_gpstd: + ;segundo byte + LD 0 (IY),A + INC IY + INC HL + POP BC + DJNZ bucle_alto_gpstd + RET + + + +byte_tmp: ;DEFS 2 + .DB #0,#0 +letra_decodificada: + .DB #0,#0,#0,#0,#0,#0,#0,#0 ;DEFS 16 + .DB #0,#0,#0,#0,#0,#0,#0,#0 ;USO ESTE ESPACIO PARA GUARDAR LA LETRA QUE SE DECODIFICA + +;DEFC direcc_destino0s_m1 = direcc_destino + +first_char8: + .DB #32 ;first defined char number (ASCII) +cpc_Chars8: ;each bit of each byte is a pixel,#same way as SYMBOL function of Locomotive BASIC. + ;; KEY SET BY ANJUEL & NA_TH_AN FROM NANAKO CPC GAME. + .DB #0,#0,#0,#0,#0,#0,#0,#0 + .DB #28,#8,#8,#8,#28,#0,#8,#0 + .DB #10,#10,#0,#0,#0,#0,#0,#0 + .DB #36,#126,#36,#36,#36,#126,#36,#0 + .DB #16,#62,#32,#60,#4,#124,#8,#0 + .DB #0,#50,#52,#8,#22,#38,#0,#0 + .DB #0,#16,#40,#58,#68,#58,#0,#0 + .DB #16,#16,#0,#0,#0,#0,#0,#0 + .DB #16,#112,#80,#64,#80,#112,#16,#0 + .DB #8,#14,#10,#2,#10,#14,#8,#0 + .DB #0,#42,#28,#28,#42,#0,#0,#0 + .DB #0,#8,#8,#62,#8,#8,#0,#0 + .DB #0,#0,#0,#0,#12,#12,#0,#0 + .DB #0,#0,#0,#62,#0,#0,#0,#0 + .DB #0,#0,#0,#0,#12,#12,#16,#0 + .DB #0,#4,#8,#16,#32,#64,#0,#0 + .DB #62,#34,#34,#34,#34,#34,#62,#0 + .DB #12,#4,#4,#4,#4,#4,#4,#0 + .DB #62,#34,#2,#62,#32,#34,#62,#0 + .DB #62,#36,#4,#28,#4,#36,#62,#0 + .DB #32,#32,#36,#62,#4,#4,#14,#0 + .DB #62,#32,#32,#62,#2,#34,#62,#0 + .DB #62,#32,#32,#62,#34,#34,#62,#0 + .DB #62,#36,#4,#4,#4,#4,#14,#0 + .DB #62,#34,#34,#62,#34,#34,#62,#0 + .DB #62,#34,#34,#62,#2,#34,#62,#0 + .DB #0,#24,#24,#0,#0,#24,#24,#0 + .DB #0,#24,#24,#0,#0,#24,#24,#32 + .DB #4,#8,#16,#32,#16,#8,#4,#0 + .DB #0,#0,#126,#0,#0,#126,#0,#0 + .DB #32,#16,#8,#4,#8,#16,#32,#0 + .DB #64,#124,#68,#4,#28,#16,#0,#16 + .DB #0,#56,#84,#92,#64,#60,#0,#0 + .DB #126,#36,#36,#36,#60,#36,#102,#0 + .DB #124,#36,#36,#62,#34,#34,#126,#0 + .DB #2,#126,#66,#64,#66,#126,#2,#0 + .DB #126,#34,#34,#34,#34,#34,#126,#0 + .DB #2,#126,#66,#120,#66,#126,#2,#0 + .DB #2,#126,#34,#48,#32,#32,#112,#0 + .DB #2,#126,#34,#32,#46,#36,#124,#0 + .DB #102,#36,#36,#60,#36,#36,#102,#0 + .DB #56,#16,#16,#16,#16,#16,#56,#0 + .DB #28,#8,#8,#8,#8,#40,#56,#0 + .DB #108,#40,#40,#124,#36,#36,#102,#0 + .DB #112,#32,#32,#32,#34,#126,#2,#0 + .DB #127,#42,#42,#42,#42,#107,#8,#0 + .DB #126,#36,#36,#36,#36,#36,#102,#0 + .DB #126,#66,#66,#66,#66,#66,#126,#0 + .DB #126,#34,#34,#126,#32,#32,#112,#0 + .DB #126,#66,#66,#74,#126,#8,#28,#0 + .DB #126,#34,#34,#126,#36,#36,#114,#0 + .DB #126,#66,#64,#126,#2,#66,#126,#0 + .DB #34,#62,#42,#8,#8,#8,#28,#0 + .DB #102,#36,#36,#36,#36,#36,#126,#0 + .DB #102,#36,#36,#36,#36,#24,#0,#0 + .DB #107,#42,#42,#42,#42,#42,#62,#0 + .DB #102,#36,#36,#24,#36,#36,#102,#0 + .DB #102,#36,#36,#60,#8,#8,#28,#0 + .DB #126,#66,#4,#8,#16,#34,#126,#0 + .DB #4,#60,#36,#32,#36,#60,#4,#0 + .DB #0,#64,#32,#16,#8,#4,#0,#0 + .DB #32,#60,#36,#4,#36,#60,#32,#0 + .DB #0,#16,#40,#68,#0,#0,#0,#0 + .DB #0,#0,#0,#0,#0,#0,#0,#0 + .DB #0,#100,#104,#16,#44,#76,#0,#0 + .DB #126,#36,#36,#36,#60,#36,#102,#0 + .DB #124,#36,#36,#62,#34,#34,#126,#0 + .DB #2,#126,#66,#64,#66,#126,#2,#0 + .DB #126,#34,#34,#34,#34,#34,#126,#0 + .DB #2,#126,#66,#120,#66,#126,#2,#0 + .DB #2,#126,#34,#48,#32,#32,#112,#0 + .DB #2,#126,#34,#32,#46,#36,#124,#0 + .DB #102,#36,#36,#60,#36,#36,#102,#0 + .DB #56,#16,#16,#16,#16,#16,#56,#0 + .DB #28,#8,#8,#8,#8,#40,#56,#0 + .DB #108,#40,#40,#124,#36,#36,#102,#0 + .DB #112,#32,#32,#32,#34,#126,#2,#0 + .DB #127,#42,#42,#42,#42,#107,#8,#0 + .DB #126,#36,#36,#36,#36,#36,#102,#0 + .DB #126,#66,#66,#66,#66,#66,#126,#0 + .DB #126,#34,#34,#126,#32,#32,#112,#0 + .DB #126,#66,#66,#74,#126,#8,#28,#0 + .DB #126,#34,#34,#126,#36,#36,#114,#0 + .DB #126,#66,#64,#126,#2,#66,#126,#0 + .DB #34,#62,#42,#8,#8,#8,#28,#0 + .DB #102,#36,#36,#36,#36,#36,#126,#0 + .DB #102,#36,#36,#36,#36,#24,#0,#0 + .DB #107,#42,#42,#42,#42,#42,#62,#0 + .DB #102,#36,#36,#24,#36,#36,#102,#0 + .DB #102,#36,#36,#60,#8,#8,#28,#0 + .DB #126,#66,#4,#8,#16,#34,#126,#0 + .DB #4,#60,#36,#96,#96,#36,#60,#4 + .DB #0,#16,#16,#16,#16,#16,#16,#0 + .DB #32,#60,#36,#6,#6,#36,#60,#32 + .DB #0,#0,#16,#40,#68,#0,#0,#0 + .DB #126,#66,#90,#82,#90,#66,#126,#0 \ No newline at end of file diff --git a/lib/cpcrslib/LICENSE b/lib/cpcrslib/LICENSE new file mode 100644 index 0000000..04424c0 --- /dev/null +++ b/lib/cpcrslib/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2008-2015 Raúl Simarro + +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/lib/cpcrslib/Makefile b/lib/cpcrslib/Makefile new file mode 100644 index 0000000..83a9d7c --- /dev/null +++ b/lib/cpcrslib/Makefile @@ -0,0 +1,23 @@ +all: cpcrslib.lib cpcwyzlib.lib + +AS=sdasz80 +AR=sdcclib +cpcrslib_SRCS=$(wildcard cpc_*.s) +cpcrslib_OBJS=$(patsubst %.s,%.rel,$(cpcrslib_SRCS)) +cpcwyzlib_OBJS=Wyz.rel + +cpcrslib.lib: $(cpcrslib_OBJS) + $(AR) -a cpcrslib.lib $(cpcrslib_OBJS) + cp cpcrslib.lib .. + +cpcwyzlib.lib: $(cpcwyzlib_OBJS) + $(AR) -a cpcwyzlib.lib $(cpcwyzlib_OBJS) + cp cpcwyzlib.lib .. + +%.rel: %.s + $(AS) -o $< + +.PHONY: clean +clean: + rm -f *.rel *.lib + diff --git a/lib/cpcrslib/Sprites.s b/lib/cpcrslib/Sprites.s new file mode 100644 index 0000000..20ed720 --- /dev/null +++ b/lib/cpcrslib/Sprites.s @@ -0,0 +1,37 @@ +; ****************************************************** +; ** Librera de rutinas SDCC para Amstrad CPC ** +; ** Ral Simarro (Artaburu) - 2009, 2012 ** +; ****************************************************** + + +;************************************* +; SPRITES +;************************************* + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/cpcrslib/TileMap.h b/lib/cpcrslib/TileMap.h new file mode 100644 index 0000000..6240bad --- /dev/null +++ b/lib/cpcrslib/TileMap.h @@ -0,0 +1,304 @@ + +.globl _tiles +.globl _pantalla_juego +.globl _tiles_tocados +.globl _posiciones_pantalla +.globl _posiciones_super_buffer +.globl _tabla_y_ancho_pantalla + + +;.globl _posicion_inicial_area_visible +;.globl _posicion_inicial_superbuffer +;.globl _ancho_pantalla_bytes +;.globl _alto_pantalla_bytes +;.globl _ancho_pantalla_bytes_visible + + +; *************************************************** +; Transparent colour for cpc_PutTrSpTileMap2b routine +;.globl _mascara1 +;.globl _mascara2 +; *************************************************** + +;.globl _tiles_ocultos_ancho0 +;.globl _tiles_ocultos_alto0 +;.globl _tiles_ocultos_ancho1 +;.globl _tiles_ocultos_alto1 + + +;.globl _posicion_inicio_pantalla_visible +;.globl _posicion_inicio_pantalla_visible_sb + + + +;.globl _tile +; *************************************************** +; Scroll Left Addresses column +; not requiered if scroll not used +.globl _ColumnScr +; *************************************************** + + +; *************************************************** +; Transparent colour for cpc_PutTrSpTileMap2b routine +; For printing sprites using transparent color (mode 0) transparent color selection is requiered. +; Seleccin color transparente. Escribir las 2 mscaras que correspondan al color elegido. +;Example colour number 7: +mascara1 = #0 +mascara2 = #0 + + +;0: #0x00, #0x00 +;1: #0x80, #0x40 +;2: #0x04, #0x08 +;3: #0x44, #0x88 +;4: #0x10, #0x20 +;5: #0x50, #0xA0 +;6: #0x14, #0x28 +;7: #0x54, #0xA8 +;8: #0x01, #0x02 +;9: #0x41, #0x82 +;10: #0x05, #0x0A +;11: #0x45, #0x8A +;12: #0x11, #0x22 +;13: #0x51, #0xA2 +;14: #0x15, #0x2A +;15: #0x55, #0xAA +; *************************************************** + + + + +;------------------------------------------------------------------------------------ +; SCREEN AND BUFFER ADDRESSES +; VALORES QUE DEFINEN EL BUFFER Y LA PANTALLA +;------------------------------------------------------------------------------------ + +posicion_inicial_area_visible = #0xc0A4 +posicion_inicial_superbuffer = #0x100 + + +;------------------------------------------------------------------------------------ + +;------------------------------------------------------------------------------------ +; TILE MAP DIMENSIONS +;------------------------------------------------------------------------------------ + +T_WIDTH = 32 ;max=40 ;dimensiones de la pantalla en tiles +T_HEIGHT = 16 ;max=20 + + +;Invisible tile margins: +T_WH = 2 +T_HH = 0 +;------------------------------------------------------------------------------------ + + +tiles_ocultos_ancho0 = T_WH +tiles_ocultos_alto0 = T_HH +tiles_ocultos_ancho1 = T_WIDTH - T_WH - 1 +tiles_ocultos_alto1 = T_HEIGHT - T_HH - 1 + +;------------------------------------------------------------------------------------ +; Other parameters (internal use) +;------------------------------------------------------------------------------------ +;------------------------------------------------------------------------------------ + +ancho_pantalla_bytes = 2*T_WIDTH ; 2*T_WIDTH; ; El ancho de pantalla influye determinantemente en numerosas rutinas que hay que actualizar si se cambia + ; OJO con el modo +alto_pantalla_bytes = 8*T_HEIGHT; +ancho_pantalla_bytes_visible = 2*T_WIDTH ;32 ; 64; ;dentro del area definida, cuanto se debe mostrar. 2*T_WIDTH + +;El tamao del buffer es ancho_pantalla_bytes*alto_pantalla_bytes + +_TileMapConf: +;------------------------------------------------------------------------------------ +;Con la definicin del mapeado hay que tener en cuenta que las coordenadas son: +;ANCHO=64 bytes (128 pixels en modo 0) +;ALTO=128 pixels +;el mximo que entra en el CPC es 20 lneas +;SI NO SE VAN A USAR TODAS LAS LINEAS, PARA AHORRA MEMORIA ES INTERESANTE COMENTARLAS +_posiciones_pantalla: ;Posiciones en las que se dibujan los tiles +.DW #posicion_inicial_area_visible+#0x50*0 +.DW #posicion_inicial_area_visible+#0x50*1 +.DW #posicion_inicial_area_visible+#0x50*2 +.DW #posicion_inicial_area_visible+#0x50*3 +.DW #posicion_inicial_area_visible+#0x50*4 +.DW #posicion_inicial_area_visible+#0x50*5 +.DW #posicion_inicial_area_visible+#0x50*6 +.DW #posicion_inicial_area_visible+#0x50*7 +.DW #posicion_inicial_area_visible+#0x50*8 +.DW #posicion_inicial_area_visible+#0x50*9 +.DW #posicion_inicial_area_visible+#0x50*10 +.DW #posicion_inicial_area_visible+#0x50*11 +.DW #posicion_inicial_area_visible+#0x50*12 +.DW #posicion_inicial_area_visible+#0x50*13 +.DW #posicion_inicial_area_visible+#0x50*14 +.DW #posicion_inicial_area_visible+#0x50*15 +.DW #posicion_inicial_area_visible+#0x50*16 +.DW #posicion_inicial_area_visible+#0x50*17 +.DW #posicion_inicial_area_visible+#0x50*18 +.DW #posicion_inicial_area_visible+#0x50*19 + +_posiciones_super_buffer: ;muestra el inicio de cada lnea (son 10 tiles de 8x16 de alto) +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*0 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*1 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*2 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*3 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*4 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*5 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*6 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*7 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*8 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*9 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*10 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*11 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*12 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*13 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*14 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*15 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*16 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*17 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*18 +.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*19 + + + + +; *************************************************** +; Scroll Left Addresses column. DECRAPTED +; not requiered if scroll not used comment it ;) +_ColumnScr: +; *************************************************** + + +_pantalla_actual: .DW #0 +_pantalla_juego: ;en tiles +;defs T_WIDTH*T_HEIGHT +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.DB #0xFF ;Este byte es importante, marca el fin de la pantalla. + + +_fondo_pantalla_juego: ;en tiles +;defs T_WIDTH*T_HEIGHT +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#13,#14,#17,#13,#14,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#15,#16,#17,#15,#16,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 +.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17 + + +_tiles_tocados: +.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF +.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF +.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF +.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF +.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF +.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF +.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF +.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF +.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF +.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF + ;defs 150 ;150 ;cuando un tile es tocado, se marca en esta tabla para luego restaurarlo. Es una tabla sin duplicados. + + +_tabla_y_ancho_pantalla: +.dw #_pantalla_juego + #0 +.dw #_pantalla_juego + #1*T_WIDTH +.dw #_pantalla_juego + #2*T_WIDTH +.dw #_pantalla_juego + #3*T_WIDTH +.dw #_pantalla_juego + #4*T_WIDTH +.dw #_pantalla_juego + #5*T_WIDTH +.dw #_pantalla_juego + #6*T_WIDTH +.dw #_pantalla_juego + #7*T_WIDTH +.dw #_pantalla_juego + #8*T_WIDTH +.dw #_pantalla_juego + #9*T_WIDTH +.dw #_pantalla_juego + #10*T_WIDTH +.dw #_pantalla_juego + #11*T_WIDTH +.dw #_pantalla_juego + #12*T_WIDTH +.dw #_pantalla_juego + #13*T_WIDTH +.dw #_pantalla_juego + #14*T_WIDTH +.dw #_pantalla_juego + #15*T_WIDTH +.dw #_pantalla_juego + #16*T_WIDTH +.dw #_pantalla_juego + #17*T_WIDTH +.dw #_pantalla_juego + #18*T_WIDTH +.dw #_pantalla_juego + #19*T_WIDTH + +;_tabla_y_x_ancho2: +;.dw #ancho_pantalla_bytes * 0 /2 +;.dw #ancho_pantalla_bytes * 1 /2 +;.dw #ancho_pantalla_bytes * 2 /2 +;.dw #ancho_pantalla_bytes * 3 /2 +;.dw #ancho_pantalla_bytes * 4 /2 +;.dw #ancho_pantalla_bytes * 5 /2 +;.dw #ancho_pantalla_bytes * 6 /2 +;.dw #ancho_pantalla_bytes * 7 /2 +;.dw #ancho_pantalla_bytes * 8 /2 +;.dw #ancho_pantalla_bytes * 9 /2 +;.dw #ancho_pantalla_bytes * 10 /2 +;.dw #ancho_pantalla_bytes * 11 /2 +;.dw #ancho_pantalla_bytes * 12 /2 +;.dw #ancho_pantalla_bytes * 13 /2 +;.dw #ancho_pantalla_bytes * 14 /2 +;.dw #ancho_pantalla_bytes * 15 /2 +;.dw #ancho_pantalla_bytes * 16 /2 +;.dw #ancho_pantalla_bytes * 17 /2 +;.dw #ancho_pantalla_bytes * 18 /2 +;.dw #ancho_pantalla_bytes * 19 /2 + + +;------------------------------------------------------------------------------------ +; TILE DATA. TILES MUST BE DEFINED HERE +;------------------------------------------------------------------------------------ + + +_tiles: ;Son de 2x8 bytes +;tile 0 +.db #0x00,#0x00 +.db #0x40,#0x00 +.db #0x40,#0x00 +.db #0x40,#0x00 +.db #0x40,#0x00 +.db #0x40,#0x00 +.db #0x40,#0xC0 +.db #0x00,#0x00 +;tile 1 +.db #0x3C,#0x00 +.db #0x3C,#0x00 +.db #0x00,#0x3C +.db #0x00,#0x3C +.db #0x3C,#0x00 +.db #0x3C,#0x00 +.db #0x00,#0x3C +.db #0x00,#0x3C +;tile 2 +.db #0x00,#0x00 +.db #0x15,#0x00 +.db #0x00,#0x2A +.db #0x15,#0x00 +.db #0x00,#0x2A +.db #0x15,#0x00 +.db #0x00,#0x00 +.db #0x00,#0x00 diff --git a/lib/cpcrslib/Wyz.s b/lib/cpcrslib/Wyz.s new file mode 100644 index 0000000..d6f7e55 --- /dev/null +++ b/lib/cpcrslib/Wyz.s @@ -0,0 +1,1403 @@ +; ****************************************************** +; ** Librera de rutinas para Amstrad CPC ** +; ** Ral Simarro, Artaburu 2010 ** +; ** PLAYER programado por WYZ ** +; ****************************************************** + +;XLIB cpc_WyzPlayer + + + +;XDEF CARGA_CANCION_WYZ +;XDEF INICIA_EFECTO_WYZ +;XDEF cpc_WyzSetPlayerOn0 +;XDEF cpc_WyzSetPlayerOff0 + +;XDEF TABLA_SONG +;XDEF TABLA_EFECTOS +;XDEF TABLA_PAUTAS +;;XDEF TABLA_SONIDOS +;XDEF INTERRUPCION + +;XDEF BUFFER_MUSICA +;XDEF direcc_tempo + + + + +;DEFINE BUFFER_DEC = #0x100 + + + + + +; CPC PSG proPLAYER - WYZ 2010 +;XREF INTERRUPCION + + +.globl _cpc_WyzConfigurePlayer + +_cpc_WyzConfigurePlayer:: + + LD HL,#2 + ADD HL,SP + LD a,(HL) + + LD (#INTERR),A + RET + + +.globl _cpc_WyzInitPlayer + +_cpc_WyzInitPlayer:: + +; la entrada indica las tablas de canciones, pautas, efectos,... slo hay que inicializar esos datos +; en la librera + LD IX,#2 + ADD IX,SP + + LD L,6 (IX) + LD H,7 (IX) + LD (#TABLA_SONG0),HL + LD L,4 (IX) + LD H,5 (IX) + LD (#TABLA_EFECTOS0),HL + LD L,2 (IX) + LD H,3 (IX) + LD (#TABLA_PAUTAS0),HL + LD L,0 (IX) + LD H,1 (IX) + LD (#TABLA_SONIDOS0),HL + RET + +.globl _cpc_WyzLoadSong + +_cpc_WyzLoadSong:: + LD HL,#2 + ADD HL,SP + LD A,(HL) + JP CARGA_CANCION_WYZ0 + + +.globl _cpc_WyzSetTempo + +_cpc_WyzSetTempo:: + LD HL,#2 + ADD HL,SP + LD A,(HL) + ld (#dir_tempo+1),a + ret + + +.globl _cpc_WyzStartEffect + +_cpc_WyzStartEffect:: + LD HL,#2 + ADD HL,SP + LD c,(HL) + INC HL + LD b,(HL) + ;AHORA TIENE 2 parmetros: C:canal, B:numero efecto + JP INICIA_EFECTO_WYZ0 + +;.globl _cpc_WyzStartSound + +;_cpc_WyzStartSound:: +; LD HL,#2 +; ADD HL,SP +; LD A,(HL) +; JP INICIA_SONIDO_WYZ + +.globl _cpc_WyzTestPlayer + +_cpc_WyzTestPlayer:: + LD HL,#INTERR + LD A,(HL) + LD L,A + LD H,#0 + RET + +_cpc_WyzPlayer:: + +;.globl _cpc_WyzSetPlayerOn +;.globl _cpc_WyzSetPlayerOn1 + +;_cpc_WyzSetPlayerOn:: +;_cpc_WyzSetPlayerOn1:: + ;El player funcionar por interrupciones. +; DI +; ld a,(#0x0038) +; ld (#datos_int),a +; ld (#salto_int),a +; ld a,(#0x0039) +; ld (#datos_int+1),a +; ld (#salto_int+1),a +; ld a,(#0x003a) +; ld (#datos_int+2),a +; ld (#salto_int+2),a +; +; ld a,#0xC3 +; ld (#0x0038),a +; ld HL,#INICIO +; ld (#0x0039),HL +; EI +; ret + +.globl _cpc_WyzSetPlayerOff +;.globl _cpc_WyzSetPlayerOff1 +_cpc_WyzSetPlayerOff:: +;_cpc_WyzSetPlayerOff1:: + + ;apago todos los sonidos poniendo los registros a 0 + call PLAYER_OFF + ret + + ;DI + ;Restaura salto original + ;ld a,(#datos_int) ;guardo el salto original + ;ld (#0x0038),A + ;ld a,(#datos_int+1) ;guardo el salto original + ;ld (#0x0039),A + ;ld a,(#datos_int+2) ;guardo el salto original + ;ld (#0x003a),A + + ;EI + ;ret + + + + + +;___________________________________________________________ + + ; .db "PSG PROPLAYER BY WYZ'10" + +;___________________________________________________________ + + +;___________________________________________________________ + +.globl _cpc_WyzPlayerISR + +_cpc_WyzPlayerISR:: + +INICIO: + + + ;primero mira si toca tocar :P + ;push af + LD A,(#contador) + DEC A + LD (#contador),A + OR #0 + JP NZ,termina_int +dir_tempo: + LD A,#6 + LD (#contador),A + + PUSH BC + PUSH HL + PUSH DE + PUSH IX + PUSH IY + + + + CALL ROUT + LD HL,#PSG_REG + LD DE,#PSG_REG_SEC + LD BC,#14 + LDIR + + + + CALL PLAY + CALL REPRODUCE_SONIDO + + LD HL,#PSG_REG_SEC + LD DE,#PSG_REG_EF + LD BC,#14 + LDIR + + ;De este modo, prevalece el efecto + CALL REPRODUCE_EFECTO_A + CALL REPRODUCE_EFECTO_B + CALL REPRODUCE_EFECTO_C + CALL ROUT_EF + + + + POP IY + POP IX + POP DE + POP HL + POP BC + +termina_int: + pop af + ei + ret +;salto_int: +;.db #0,#0,#0 + + + +contador: .db #0 +;datos_int: .db #0,#0,#0 ; Se guardan 3 BYTES!!!! (Dedicado a Na_th_an, por los desvelos) + + + +;INICIA EL SONIDO N (A) + +;INICIA EL SONIDO N (A) + +INICIA_EFECTO_WYZ0: + +;INICIA EL SONIDO N (B) EN EL CANAL (C) + LD A,C + CP #0 + JP Z,INICIA_EFECTO_A + CP #1 + JP Z,INICIA_EFECTO_B + CP #2 + JP Z,INICIA_EFECTO_C + ;JP INICIA_EFECTO_A + RET + + +;REPRODUCE EFECTOS + + + + +;REPRODUCE EFECTOS CANAL A + + +REPRODUCE_EFECTO_A: + LD HL,#INTERR + BIT 3,(HL) ;ESTA ACTIVADO EL EFECTO? + RET Z + LD HL,(#PUNTERO_EFECTO_A) + LD A,(HL) + CP #0xFF + JR Z,FIN_EFECTO_A + CALL BLOQUE_COMUN + LD (#PUNTERO_EFECTO_A),HL + LD 0 (IX),B + LD 1 (IX),C + LD 8 (IX),A + RET +FIN_EFECTO_A: + LD HL,#INTERR + RES 3,(HL) + XOR A + LD (#PSG_REG_EF+0),A + LD (#PSG_REG_EF+1),A + LD (#PSG_REG_EF+8),A + RET + +REPRODUCE_EFECTO_B: + LD HL,#INTERR + BIT 5,(HL) ;ESTA ACTIVADO EL EFECTO? + RET Z + LD HL,(#PUNTERO_EFECTO_B) + LD A,(HL) + CP #0xFF + JR Z,FIN_EFECTO_B + CALL BLOQUE_COMUN + LD (#PUNTERO_EFECTO_B),HL + LD 2 (IX),B + LD 3 (IX),C + LD 9 (IX),A + RET +FIN_EFECTO_B: + LD HL,#INTERR + RES 5,(HL) + XOR A + LD (#PSG_REG_EF+2),A + LD (#PSG_REG_EF+3),A + LD (#PSG_REG_EF+9),A + RET + +REPRODUCE_EFECTO_C: + LD HL,#INTERR + BIT 6,(HL) ;ESTA ACTIVADO EL EFECTO? + RET Z + LD HL,(#PUNTERO_EFECTO_C) + LD A,(HL) + CP #0xFF + JR Z,FIN_EFECTO_C + CALL BLOQUE_COMUN + LD (#PUNTERO_EFECTO_C),HL + LD 4 (IX),B + LD 5 (IX),C + LD 10 (IX),A + RET +FIN_EFECTO_C: + LD HL,#INTERR + RES 6,(HL) + XOR A + LD (#PSG_REG_EF+4),A + LD (#PSG_REG_EF+5),A + LD (#PSG_REG_EF+10),A + RET + +BLOQUE_COMUN: + LD IX,#PSG_REG_EF + LD B,A + INC HL + LD A,(HL) + RRCA + RRCA + RRCA + RRCA + AND #0b00001111 + LD C,A + LD A,(HL) + AND #0b00001111 + INC HL + RET + +INICIA_EFECTO_A: + LD A,B + LD HL,(#TABLA_EFECTOS0) + CALL EXT_WORD + LD (#PUNTERO_EFECTO_A),HL + LD HL,#INTERR + SET 3,(HL) + RET + +INICIA_EFECTO_B: + LD A,B + LD HL,(#TABLA_EFECTOS0) + CALL EXT_WORD + LD (#PUNTERO_EFECTO_B),HL + LD HL,#INTERR + SET 5,(HL) + RET + +INICIA_EFECTO_C: + LD A,B + LD HL,(#TABLA_EFECTOS0) + CALL EXT_WORD + LD (#PUNTERO_EFECTO_C),HL + LD HL,#INTERR + SET 6,(HL) + RET + + + +INICIA_SONIDO: + LD HL,(#TABLA_SONIDOS0) + CALL EXT_WORD + LD (#PUNTERO_SONIDO),HL + LD HL,#INTERR + SET 2,(HL) + RET +;PLAYER OFF + +PLAYER_OFF: + LD HL,#INTERR + RES 1,(HL) + + XOR A + LD HL,#PSG_REG + LD DE,#PSG_REG+1 + LD BC,#14 + LD (HL),A + LDIR + + LD HL,#PSG_REG_SEC + LD DE,#PSG_REG_SEC+1 + LD BC,#14 + LD (HL),A + LDIR + + CALL ROUT + CALL FIN_SONIDO + RET + + + + +CARGA_CANCION_WYZ0: + DI + push af + CALL PLAYER_OFF + pop af +; MUSICA DATOS INICIALES + + + + + LD DE,#0x0010 ; N BYTES RESERVADOS POR CANAL + LD HL,#BUFFER_DEC ;* RESERVAR MEMORIA PARA BUFFER DE SONIDO!!!!! + LD (#CANAL_A),HL + + ADD HL,DE + LD (#CANAL_B),HL + + ADD HL,DE + LD (#CANAL_C),HL + + ADD HL,DE + LD (#CANAL_P),HL + + ;LD A,#0 ;* CANCION N 0 + CALL CARGA_CANCION + + LD A,#6 + LD (#contador),A + +;PANTALLA + EI + ret + + + +;CARGA UNA CANCION +;IN:(A)=N DE CANCION + +CARGA_CANCION: + LD HL,#INTERR ;CARGA CANCION + + SET 1,(HL) ;REPRODUCE CANCION + LD HL,#SONG + LD (HL),A ;N A + + + +;DECODIFICAR +;IN-> INTERR 0 ON +; SONG + +;CARGA CANCION SI/NO + +DECODE_SONG: + LD A,(#SONG) + +;LEE CABECERA DE LA CANCION +;BYTE 0=TEMPO + + ;LD HL,TABLA_SONG + LD HL,(#TABLA_SONG0) + CALL EXT_WORD + LD A,(HL) + LD (#TEMPO),A + XOR A + LD (#TTEMPO),A + +;HEADER BYTE 1 +;(-|-|-|-|-|-|-|LOOP) + + INC HL ;LOOP 1=ON/0=OFF? + LD A,(HL) + BIT 0,A + JR Z,NPTJP0 + PUSH HL + LD HL,#INTERR + SET 4,(HL) + POP HL + + +NPTJP0: + INC HL ;2 BYTES RESERVADOS + INC HL + INC HL + +;BUSCA Y GUARDA INICIO DE LOS CANALES EN EL MODULO MUS + + + LD (#PUNTERO_P_DECA),HL + LD E,#0x3F ;CODIGO INTRUMENTO 0 + LD B,#0xFF ;EL MODULO DEBE TENER UNA LONGITUD MENOR DE #0xFF00 ... o_O! +BGICMODBC1: + XOR A ;BUSCA EL BYTE 0 + CPIR + DEC HL + DEC HL + LD A,E ;ES EL INSTRUMENTO 0?? + CP (HL) + INC HL + INC HL + JR Z,BGICMODBC1 + + LD (#PUNTERO_P_DECB),HL + +BGICMODBC2: + XOR A ;BUSCA EL BYTE 0 + CPIR + DEC HL + DEC HL + LD A,E + CP (HL) ;ES EL INSTRUMENTO 0?? + INC HL + INC HL + JR Z,BGICMODBC2 + + LD (#PUNTERO_P_DECC),HL + +BGICMODBC3: + XOR A ;BUSCA EL BYTE 0 + CPIR + DEC HL + DEC HL + LD A,E + CP (HL) ;ES EL INSTRUMENTO 0?? + INC HL + INC HL + JR Z,BGICMODBC3 + LD (#PUNTERO_P_DECP),HL + + +;LEE DATOS DE LAS NOTAS +;(|)(|||||) LONGITUD\NOTA + +INIT_DECODER: + LD DE,(#CANAL_A) + LD (#PUNTERO_A),DE + LD HL,(#PUNTERO_P_DECA) + CALL DECODE_CANAL ;CANAL A + LD (#PUNTERO_DECA),HL + + LD DE,(#CANAL_B) + LD (#PUNTERO_B),DE + LD HL,(#PUNTERO_P_DECB) + CALL DECODE_CANAL ;CANAL B + LD (#PUNTERO_DECB),HL + + LD DE,(#CANAL_C) + LD (#PUNTERO_C),DE + LD HL,(#PUNTERO_P_DECC) + CALL DECODE_CANAL ;CANAL C + LD (#PUNTERO_DECC),HL + + LD DE,(#CANAL_P) + LD (#PUNTERO_P),DE + LD HL,(#PUNTERO_P_DECP) + CALL DECODE_CANAL ;CANAL P + LD (#PUNTERO_DECP),HL + + RET + + +;DECODIFICA NOTAS DE UN CANAL +;IN (DE)=DIRECCION DESTINO +;NOTA=0 FIN CANAL +;NOTA=1 SILENCIO +;NOTA=2 PUNTILLO +;NOTA=3 COMANDO I + +DECODE_CANAL: + LD A,(HL) + AND A ;FIN DEL CANAL? + JR Z,FIN_DEC_CANAL + CALL GETLEN + + CP #0b00000001 ;ES SILENCIO? + JR NZ,NO_SILENCIO + SET 6,A + JR NO_MODIFICA + +NO_SILENCIO: + CP #0b00111110 ;ES PUNTILLO? + JR NZ,NO_PUNTILLO + OR A + RRC B + XOR A + JR NO_MODIFICA + +NO_PUNTILLO: + CP #0b00111111 ;ES COMANDO? + JR NZ,NO_MODIFICA + BIT 0,B ;COMADO=INSTRUMENTO? + JR Z,NO_INSTRUMENTO + LD A,#0b11000001 ;CODIGO DE INSTRUMENTO + LD (DE),A + INC HL + INC DE + LD A,(HL) ;N DE INSTRUMENTO + LD (DE),A + INC DE + INC HL + JR DECODE_CANAL + +NO_INSTRUMENTO: + BIT 2,B + JR Z,NO_ENVOLVENTE + LD A,#0b11000100 ;CODIGO ENVOLVENTE + LD (DE),A + INC DE + INC HL + JR DECODE_CANAL + +NO_ENVOLVENTE: + BIT 1,B + JR Z,NO_MODIFICA + LD A,#0b11000010 ;CODIGO EFECTO + LD (DE),A + INC HL + INC DE + LD A,(HL) + CALL GETLEN + +NO_MODIFICA: + LD (DE),A + INC DE + XOR A + DJNZ NO_MODIFICA + SET 7,A + SET 0,A + LD (DE),A + INC DE + INC HL + RET ;** JR DECODE_CANAL + +FIN_DEC_CANAL: + SET 7,A + LD (DE),A + INC DE + RET + +GETLEN: + LD B,A + AND #0b00111111 + PUSH AF + LD A,B + AND #0b11000000 + RLCA + RLCA + INC A + LD B,A + LD A,#0b10000000 +DCBC0: + RLCA + DJNZ DCBC0 + LD B,A + POP AF + RET + + + + + + +;PLAY __________________________________________________ + + +PLAY: + LD HL,#INTERR ;PLAY BIT 1 ON? + BIT 1,(HL) + RET Z +;TEMPO + LD HL,#TTEMPO ;CONTADOR TEMPO + INC (HL) + LD A,(#TEMPO) + CP (HL) + JR NZ,PAUTAS + LD (HL),#0 + +;INTERPRETA + LD IY,#PSG_REG + LD IX,#PUNTERO_A + LD BC,#PSG_REG+8 + CALL LOCALIZA_NOTA + LD IY,#PSG_REG+2 + LD IX,#PUNTERO_B + LD BC,#PSG_REG+9 + CALL LOCALIZA_NOTA + LD IY,#PSG_REG+4 + LD IX,#PUNTERO_C + LD BC,#PSG_REG+10 + CALL LOCALIZA_NOTA + LD IX,#PUNTERO_P ;EL CANAL DE EFECTOS ENMASCARA OTRO CANAL + CALL LOCALIZA_EFECTO + +;PAUTAS + +PAUTAS: + LD IY,#PSG_REG+0 + LD IX,#PUNTERO_P_A + LD HL,#PSG_REG+8 + CALL PAUTA ;PAUTA CANAL A + LD IY,#PSG_REG+2 + LD IX,#PUNTERO_P_B + LD HL,#PSG_REG+9 + CALL PAUTA ;PAUTA CANAL B + LD IY,#PSG_REG+4 + LD IX,#PUNTERO_P_C + LD HL,#PSG_REG+10 + CALL PAUTA ;PAUTA CANAL C + + RET + + + +;REPRODUCE EFECTOS DE SONIDO + +REPRODUCE_SONIDO: + + LD HL,#INTERR + BIT 2,(HL) ;ESTA ACTIVADO EL EFECTO? + RET Z + LD HL,(#PUNTERO_SONIDO) + LD A,(HL) + CP #0xFF + JR Z,FIN_SONIDO + LD (#PSG_REG_SEC+4),A + INC HL + LD A,(HL) + RRCA + RRCA + RRCA + RRCA + AND #0b00001111 + LD (#PSG_REG_SEC+5),A + LD A,(HL) + AND #0b00001111 + LD (#PSG_REG_SEC+10),A + INC HL + LD A,(HL) + AND A + JR Z,NO_RUIDO + LD (#PSG_REG_SEC+6),A + LD A,#0b10011000 + JR SI_RUIDO +NO_RUIDO: + LD A,#0b10111000 +SI_RUIDO: + LD (#PSG_REG_SEC+7),A + + INC HL + LD (#PUNTERO_SONIDO),HL + RET +FIN_SONIDO: + LD HL,#INTERR + RES 2,(HL) + +FIN_NOPLAYER: + LD A,#0b10111000 ;2 BITS ALTOS PARA MSX / AFECTA AL CPC??? + LD (#PSG_REG+7),A + RET + +;VUELCA BUFFER DE SONIDO AL PSG + +;VUELCA BUFFER DE SONIDO AL PSG + +ROUT: + XOR A + LD HL,#PSG_REG_SEC +LOUT: + CALL WRITEPSGHL + INC A + CP #13 + JR NZ,LOUT + LD A,(HL) + AND A + RET Z + LD A,#13 + CALL WRITEPSGHL + XOR A + LD (#PSG_REG+13),A + LD (#PSG_REG_SEC+13),A + RET + + +ROUT_EF: + XOR A + LD HL,#PSG_REG_EF +LOUT_EF: + CALL WRITEPSGHL + INC A + CP #13 + JR NZ,LOUT_EF + LD A,(HL) + AND A + RET Z + LD A,#13 + CALL WRITEPSGHL + XOR A + LD (#PSG_REG_EF+13),A + RET +;; A = REGISTER +;; (HL) = VALUE +WRITEPSGHL: + LD B,#0xF4 + OUT (C),A + LD BC,#0xF6C0 + OUT (C),C + .db #0xED + .db #0x71 + LD B,#0xF5 + OUTI + LD BC,#0xF680 + OUT (C),C + .db #0xED + .db #0x71 + RET + +;LOCALIZA NOTA CANAL A +;IN (PUNTERO_A) + +LOCALIZA_NOTA: + LD L,0 (IX) ;HL=(PUNTERO_A_C_B) + LD H,1 (IX) + LD A,(HL) + AND #0b11000000 ;COMANDO? + CP #0b11000000 + JR NZ,LNJP0 + +;BIT(0)=INSTRUMENTO + +COMANDOS: + LD A,(HL) + BIT 0,A ;INSTRUMENTO + JR Z,COM_EFECTO + + INC HL + LD A,(HL) ;N DE PAUTA + INC HL + LD 0 (IX),L + LD 1 (IX),H + ;LD HL,TABLA_PAUTAS + LD HL,(#TABLA_PAUTAS0) + CALL EXT_WORD + LD 18 (IX),L + LD 19 (IX),H + LD 12 (IX),L + LD 13 (IX),H + LD L,C + LD H,B + RES 4,(HL) ;APAGA EFECTO ENVOLVENTE + XOR A + LD (#PSG_REG_SEC+13),A + LD (#PSG_REG+13),A + JR LOCALIZA_NOTA + +COM_EFECTO: + BIT 1,A ;EFECTO DE SONIDO + JR Z,COM_ENVOLVENTE + + INC HL + LD A,(HL) + INC HL + LD 0 (IX),L + LD 1 (IX),H + CALL INICIA_SONIDO + RET + +COM_ENVOLVENTE: + BIT 2,A + RET Z ;IGNORA - ERROR + + INC HL + LD 0 (IX),L + LD 1 (IX),H + LD L,C + LD H,B + LD (HL),#0b00010000 ;ENCIENDE EFECTO ENVOLVENTE + JR LOCALIZA_NOTA + + +LNJP0: + LD A,(HL) + INC HL + BIT 7,A + JR Z,NO_FIN_CANAL_A ; + BIT 0,A + JR Z,FIN_CANAL_A + +FIN_NOTA_A: + LD E,6 (IX) + LD D,7 (IX) ;PUNTERO BUFFER AL INICIO + LD 0 (IX),E + LD 1 (IX),D + LD L,30 (IX) ;CARGA PUNTERO DECODER + LD H,31 (IX) + PUSH BC + CALL DECODE_CANAL ;DECODIFICA CANAL + POP BC + LD 30 (IX),L ;GUARDA PUNTERO DECODER + LD 31 (IX),H + JP LOCALIZA_NOTA + +FIN_CANAL_A: + LD HL,#INTERR ;LOOP? + BIT 4,(HL) + JR NZ,FCA_CONT + CALL PLAYER_OFF + RET + +FCA_CONT: + LD L,24 (IX) ;CARGA PUNTERO INICIAL DECODER + LD H,25 (IX) + LD 30 (IX),L + LD 31 (IX),H + JR FIN_NOTA_A + +NO_FIN_CANAL_A: + LD 0 (IX),L ;(PUNTERO_A_B_C)=HL GUARDA PUNTERO + LD 1 (IX),H + AND A ;NO REPRODUCE NOTA SI NOTA=0 + JR Z,FIN_RUTINA + BIT 6,A ;SILENCIO? + JR Z,NO_SILENCIO_A + LD A,(BC) + AND #0b00010000 + JR NZ,SILENCIO_ENVOLVENTE + XOR A + LD (BC),A ;RESET VOLUMEN + LD 0 (IY),A + LD 1 (IY),A + RET + +SILENCIO_ENVOLVENTE: + LD A,#0xFF + LD (#PSG_REG+11),A + LD (#PSG_REG+12),A + XOR A + LD (#PSG_REG+13),A + LD 0 (IY),A + LD 1 (IY),A + RET + +NO_SILENCIO_A: + CALL NOTA ;REPRODUCE NOTA + LD L,18 (IX) ;HL=(PUNTERO_P_A0) RESETEA PAUTA + LD H,19 (IX) + LD 12 (IX),L ;(PUNTERO_P_A)=HL + LD 13 (IX),H +FIN_RUTINA: + RET + + +;LOCALIZA EFECTO +;IN HL=(PUNTERO_P) + +LOCALIZA_EFECTO: + LD L,0 (IX) ;HL=(PUNTERO_P) + LD H,1 (IX) + LD A,(HL) + CP #0b11000010 + JR NZ,LEJP0 + + INC HL + LD A,(HL) + INC HL + LD 0 (IX),L + LD 1 (IX),H + CALL INICIA_SONIDO + RET + + +LEJP0: + INC HL + BIT 7,A + JR Z,NO_FIN_CANAL_P ; + BIT 0,A + JR Z,FIN_CANAL_P +FIN_NOTA_P: + LD DE,(#CANAL_P) + LD 0 (IX),E + LD 1 (IX),D + LD HL,(#PUNTERO_DECP) ;CARGA PUNTERO DECODER + PUSH BC + CALL DECODE_CANAL ;DECODIFICA CANAL + POP BC + LD (#PUNTERO_DECP),HL ;GUARDA PUNTERO DECODER + JP LOCALIZA_EFECTO + +FIN_CANAL_P: + LD HL,(#PUNTERO_P_DECP) ;CARGA PUNTERO INICIAL DECODER + LD (#PUNTERO_DECP),HL + JR FIN_NOTA_P + +NO_FIN_CANAL_P: + LD 0 (IX),L ;(PUNTERO_A_B_C)=HL GUARDA PUNTERO + LD 1 (IX),H + RET + +; PAUTA DE LOS 3 CANALES +; IN:(IX):PUNTERO DE LA PAUTA +; (HL):REGISTRO DE VOLUMEN +; (IY):REGISTROS DE FRECUENCIA + +; FORMATO PAUTA +; 7 6 5 4 3-0 3-0 +; BYTE 1 (LOOP|OCT-1|OCT+1|SLIDE|VOL) - BYTE 2 ( | | | |PITCH) + +PAUTA: + BIT 4,(HL) ;SI LA ENVOLVENTE ESTA ACTIVADA NO ACTUA PAUTA + RET NZ + + LD A,0 (IY) + LD B,1 (IY) + OR B + RET Z + + + PUSH HL + ;LD L,(IX+0) + ;LD H,(IX+1) + + ;LD A,(HL) ;COMPRUEBA SLIDE BIT 4 + ;BIT 4,A + ;JR Z,PCAJP4 + ;LD L,(IY+0) ;FRECUENCIA FINAL + ;LD H,(IY+1) + ;SBC HL,DE + ;JR Z,PCAJP4 + ;JR C,SLIDE_POS + ;EX DE,HL + ;RRC D ;/4 + ;RR E + ;RRC D + ;RR E + + + ;ADC HL,DE + ;LD (IY+0),L + ;LD (IY+1),H +SLIDE_POS: + ;POP HL + ;RET + +PCAJP4: + LD L,0 (IX) + LD H,1 (IX) + LD A,(HL) + + BIT 7,A ;LOOP / EL RESTO DE BITS NO AFECTAN + JR Z,PCAJP0 + AND #0b00011111 ;LOOP PAUTA (0,32)X2!!!-> PARA ORNAMENTOS + RLCA ;X2 + LD D,#0 + LD E,A + SBC HL,DE + LD A,(HL) + +PCAJP0: + BIT 6,A ;OCTAVA -1 + JR Z,PCAJP1 + LD E,0 (IY) + LD D,1 (IY) + + AND A + RRC D + RR E + LD 0 (IY),E + LD 1 (IY),D + JR PCAJP2 + +PCAJP1: + BIT 5,A ;OCTAVA +1 + JR Z,PCAJP2 + LD E,0 (IY) + LD D,1 (IY) + + AND A + RLC E + RL D + LD 0 (IY),E + LD 1 (IY),D + + +PCAJP2: + INC HL + PUSH HL + LD E,A + LD A,(HL) ;PITCH DE FRECUENCIA + LD L,A + AND A + LD A,E + JR Z,ORNMJP1 + + LD A,0 (IY) ;SI LA FRECUENCIA ES 0 NO HAY PITCH + ADD A,1 (IY) + AND A + LD A,E + JR Z,ORNMJP1 + + + BIT 7,L + JR Z,ORNNEG + LD H,#0xFF + JR PCAJP3 +ORNNEG: + LD H,#0 + +PCAJP3: + LD E,0 (IY) + LD D,1 (IY) + ADC HL,DE + LD 0 (IY),L + LD 1 (IY),H +ORNMJP1: + POP HL + + INC HL + LD 0 (IX),L + LD 1 (IX),H +PCAJP5: + POP HL + AND #0b00001111 ;VOLUMEN FINAL + LD (HL),A + RET + + + +;NOTA : REPRODUCE UNA NOTA +;IN (A)=CODIGO DE LA NOTA +; (IY)=REGISTROS DE FRECUENCIA + + +NOTA: + ;ADD 6 ;************************* + LD L,C + LD H,B + BIT 4,(HL) + LD B,A + JR NZ,EVOLVENTES + LD A,B + LD HL,#DATOS_NOTAS + RLCA ;X2 + LD D,#0 + LD E,A + ADD HL,DE + LD A,(HL) + LD 0 (IY),A + INC HL + LD A,(HL) + LD 1 (IY),A + RET + +;IN (A)=CODIGO DE LA ENVOLVENTE +; (IY)=REGISTRO DE FRECUENCIA + +EVOLVENTES: + PUSH AF + CALL ENV_RUT1 + LD DE,#0x0000 + LD 0 (IY),E + LD 1 (IY),D + + POP AF + ADD A,#48 + CALL ENV_RUT1 + + + LD A,E + LD (#PSG_REG+11),A + LD A,D + LD (#PSG_REG+12),A + LD A,#0x0E + LD (#PSG_REG+13),A + RET + +;IN(A) NOTA +ENV_RUT1: + LD HL,#DATOS_NOTAS + RLCA ;X2 + LD D,#0 + LD E,A + ADD HL,DE + LD E,(HL) + INC HL + LD D,(HL) + RET + + + +EXT_WORD: + LD D,#0 + SLA A ;*2 + LD E,A + ADD HL,DE + LD E,(HL) + INC HL + LD D,(HL) + EX DE,HL + RET + +;BANCO DE INSTRUMENTOS 2 BYTES POR INT. + +;(0)(RET 2 OFFSET) +;(1)(+-PITCH) + + +;BANCO DE INSTRUMENTOS 2 BYTES POR INT. + +;(0)(RET 2 OFFSET) +;(1)(+-PITCH) + +;.TABLA_PAUTAS .dw PAUTA_1,PAUTA_2,PAUTA_3,PAUTA_4,PAUTA_5,PAUTA_6,PAUTA_7;,PAUTA_8,PAUTA_9,PAUTA_10,PAUTA_11,PAUTA_12,PAUTA_13,PAUTA_14,PAUTA_15,PAUTA_16,PAUTA_17,PAUTA_18 + + + + + + + + + + + +;DATOS DE LOS EFECTOS DE SONIDO + +;EFECTOS DE SONIDO + + + +;.TABLA_SONIDOS .dw SONIDO1,SONIDO2,SONIDO3,SONIDO4,SONIDO5;,SONIDO6,SONIDO7;,SONIDO8 + +TABLA_PAUTAS0: .dw 0 + +TABLA_SONIDOS0: .dw 0 + + +;DATOS MUSICA + + + +;TABLA_SONG: .dw SONG_0;,SONG_1,SONG_2;,SONG_3 ;******** TABLA DE DIRECCIONES DE ARCHIVOS MUS + +;DATOS_NOTAS: .INCBIN "C:/EM/BRMSX/PLAYER/NOTAS.DAT" ;DATOS DE LAS NOTAS + + +DATOS_NOTAS: + .dw #0x0000,#0x0000 + +; .dw #0x41D,#0x3E2,#0x3AA,#0x376,#0x344,#0x315,#0x2E9,#0x2BF,#0x297,#0x272,#0x24F,#0x22E,#0x20E,#0x1F1,#0x1D5,#0x1BB +; .dw #0x1A2,#0x18A,#0x174,#0x15F,#0x14B,#0x139,#0x127,#0x117,#0x107,#0xF8,#0xEA,#0xDD +; .dw #0xD1,#0xC5,#0xBA,#0xAF,#0xA5,#0x9C,#0x93,#0x8B,#0x83,#0x7C,#0x75,#0x6E +; .dw #0x68,#0x62,#0x5D,#0x57,#0x52,#0x4E,#0x49,#0x45,#0x41,#0x3E,#0x3A,#0x37 +; .dw #0x34,#0x31,#0x2E,#0x2B,#0x29,#0x27,#0x24,#0x22,#0x20,#0x1F,#0x1D,#0x1B +; .dw #0x1A,#0x18,#0x17,#0x15,#0x14,#0x13,#0x12,#0x11,#0x10,#0xF,#0xE,#0xD + + +.DW #1711,#1614,#1524,#1438,#1358,#1281,#1210,#1142,#1078,#1017 +.DW #960,#906,#855,#807,#762,#719,#679,#641,#605,#571 +.DW #539,#509,#480,#453,#428,#404,#381,#360,#339,#320 +.DW #302,#285,#269,#254,#240,#227,#214,#202,#190,#180 +.DW #170,#160,#151,#143,#135,#127,#120,#113,#107,#101 +.DW #95,#90,#85,#80,#76,#71,#67,#64,#60,#57 + + +SONG_0: + ;INCBIN "WYAZOW.MUS" + + + +; VARIABLES__________________________ + + +INTERR: + .db #0 ;INTERRUPTORES 1=ON 0=OFF + ;BIT 0=CARGA CANCION ON/OFF + ;BIT 1=PLAYER ON/OFF + ;BIT 2=SONIDOS ON/OFF + ;BIT 3=EFECTOS ON/OFF + +;MUSICA **** EL ORDEN DE LAS VARIABLES ES FIJO ****** + +TABLA_SONG0: .dw #0 +TABLA_EFECTOS0: .dw #0 + +;.db 'P','S','G',' ','P','R','O','P','L','A','Y','E','R',' ','B','Y',' ','W','Y','Z','-','1','0' + + +SONG: .db #00 ;DBN DE CANCION +TEMPO: .db #00 ;.dbTEMPO +TTEMPO: .db #00 ;.dbCONTADOR TEMPO +PUNTERO_A: .dw #00 ;DW PUNTERO DEL CANAL A +PUNTERO_B: .dw #00 ;DW PUNTERO DEL CANAL B +PUNTERO_C: .dw #00 ;DW PUNTERO DEL CANAL C + +BUFFER_MUSICA: +CANAL_A: .dw #BUFFER_DEC ;DW DIRECION DE INICIO DE LA MUSICA A +CANAL_B: .dw #00 ;DW DIRECION DE INICIO DE LA MUSICA B +CANAL_C: .dw #00 ;DW DIRECION DE INICIO DE LA MUSICA C + +PUNTERO_P_A: .dw #00 ;DW PUNTERO PAUTA CANAL A +PUNTERO_P_B: .dw #00 ;DW PUNTERO PAUTA CANAL B +PUNTERO_P_C: .dw #00 ;DW PUNTERO PAUTA CANAL C + +PUNTERO_P_A0: .dw #00 ;DW INI PUNTERO PAUTA CANAL A +PUNTERO_P_B0: .dw #00 ;DW INI PUNTERO PAUTA CANAL B +PUNTERO_P_C0: .dw #00 ;DW INI PUNTERO PAUTA CANAL C + + +PUNTERO_P_DECA: .dw #00 ;DW PUNTERO DE INICIO DEL DECODER CANAL A +PUNTERO_P_DECB: .dw #00 ;DW PUNTERO DE INICIO DEL DECODER CANAL B +PUNTERO_P_DECC: .dw #00 ;DW PUNTERO DE INICIO DEL DECODER CANAL C + +PUNTERO_DECA: .dw #00 ;DW PUNTERO DECODER CANAL A +PUNTERO_DECB: .dw #00 ;DW PUNTERO DECODER CANAL B +PUNTERO_DECC: .dw #00 ;DW PUNTERO DECODER CANAL C + + +;CANAL DE EFECTOS - ENMASCARA OTRO CANAL + +PUNTERO_P: .dw #00 ;DW PUNTERO DEL CANAL EFECTOS +CANAL_P: .dw #00 ;DW DIRECION DE INICIO DE LOS EFECTOS +PUNTERO_P_DECP: .dw #00 ;DW PUNTERO DE INICIO DEL DECODER CANAL P +PUNTERO_DECP: .dw #00 ;DW PUNTERO DECODER CANAL P + +PSG_REG: .db #00,#00,#00,#00,#00,#00,#00,#0b10111000 ,#00,#00,#00,#00,#00,#00,#00 ;.db(11) BUFFER DE REGISTROS DEL PSG +PSG_REG_SEC: .db #00,#00,#00,#00,#00,#00,#00,#0b10111000 ,#00,#00,#00,#00,#00,#00,#00 ;.db(11) BUFFER SECUNDARIO DE REGISTROS DEL PSG + +PSG_REG_EF: .db #00,#00,#00,#00,#00,#00,#00,#0b10111000 ,#00,#00,#00,#00,#00,#00,#00 ;.db(11) BUFFER DE REGISTROS DEL PSG + +;ENVOLVENTE_A EQU #0xD033 ;DB +;ENVOLVENTE_B EQU #0xD034 ;DB +;ENVOLVENTE_C EQU #0xD035 ;DB + + + + +;EFECTOS DE SONIDO + +N_SONIDO: .db #0 ;.db NUMERO DE SONIDO +PUNTERO_SONIDO: .dw #0 ;.dw PUNTERO DEL SONIDO QUE SE REPRODUCE + +;EFECTOS + +N_EFECTO: .db #0 ;.db NUMERO DE SONIDO +;PUNTERO_EFECTO .dw 0 ;.dw PUNTERO DEL SONIDO QUE SE REPRODUCE + +PUNTERO_EFECTO_A: .dw #0 ;DW : PUNTERO DEL SONIDO QUE SE REPRODUCE +PUNTERO_EFECTO_B: .dw #0 ;DW : PUNTERO DEL SONIDO QUE SE REPRODUCE +PUNTERO_EFECTO_C: .dw #0 ;DW : PUNTERO DEL SONIDO QUE SE REPRODUCE + + + + + + + + + + + +BUFFER_DEC: ; defs #0x40 +.dw #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 ; 16 bytes +.dw #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 ; 32 bytes +.dw #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 ; 48 bytes +.dw #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 ; 64 bytes + + +; .db #0x00 ;************************* mucha atencion!!!! +;.BUFFER_DEC defs 2048 ;space dinamically asigned in source code compilation!! + ; aqui se decodifica la cancion hay que dejar suficiente espacio libre. + ;************************* + +;DEFC CARGA_CANCION_WYZ = CARGA_CANCION_WYZ0 +;DEFC INICIA_EFECTO_WYZ = INICIA_EFECTO_WYZ0 +;DEFC cpc_WyzSetPlayerOn0 = cpc_WyzSetPlayerOn1 +;DEFC cpc_WyzSetPlayerOff0 = cpc_WyzSetPlayerOff1 +;DEFC TABLA_SONG = TABLA_SONG0 +;DEFC TABLA_EFECTOS = TABLA_EFECTOS0 +;DEFC TABLA_PAUTAS = TABLA_PAUTAS0 +;DEFC TABLA_SONIDOS = TABLA_SONIDOS0 +;DEFC INTERRUPCION = INTERR +;DEFC direcc_tempo = dir_tempo diff --git a/lib/cpcrslib/cpc_ClrScr.s b/lib/cpcrslib/cpc_ClrScr.s new file mode 100644 index 0000000..49f1d2d --- /dev/null +++ b/lib/cpcrslib/cpc_ClrScr.s @@ -0,0 +1,11 @@ +.globl _cpc_ClrScr + +_cpc_ClrScr:: + XOR A + LD HL,#0xC000 + LD DE,#0xC001 + LD BC,#16383 + LD (HL),A + LDIR + RET + diff --git a/lib/cpcrslib/cpc_CollSp.s b/lib/cpcrslib/cpc_CollSp.s new file mode 100644 index 0000000..08bd02a --- /dev/null +++ b/lib/cpcrslib/cpc_CollSp.s @@ -0,0 +1,126 @@ +.globl _cpc_CollSp + +_cpc_CollSp:: +;first parameter sprite +;second parameter value + ld hl,#2 + add hl,sp + + ;ld ix,#2 + ;add ix,sp +; ld e,2 (ix) +; ld d,3 (ix) + ;A=x value +; ld l,0 (ix) +; ld h,1 (ix) + + ld e,(hl) + inc hl + ld d,(hl) + push de + inc hl + ld e,(hl) + inc hl + ld d,(hl) + push de + + pop iy ;ix sprite2 data + + pop ix ;iy sprite1 data + + ;Sprite coords & sprite dims + +;COLISION_sprites + + + +;entran sprite1 y sprite 2 y se actualizan los datos +;ix apunta a sprite1 +;iy apunta a sprite2 + +;coordenadas + ld l,8 (ix) + ld h,9 (ix) + LD (#SPR2X),HL + + ld l,8 (iy) + ld h,9 (iy) + LD (#SPR1X),HL + +;dimensiones sprite 1 + ld l,0 (ix) + ld h,1 (ix) + ld b,(hl) + inc hl + ld c,(hl) +;dimensiones sprite 12 + ld l,0 (iy) + ld h,1 (iy) + ld d,(hl) + inc hl + ld e,(hl) + + + ;ld e,(ix+6) + ;ld d,(ix+7) + + + +;ld de,DIMENSIONES_SP_PPAL ;dimensiones sprite 2 +;ld bc,DIMENSIONES_SP_PPAL ;dimensiones sprite 1 +CALL TOCADO +;RET NC ;vuelve si no hay colision +ld h,#0 +JP nc,no_colision +;Aquí hay colisión +ld l,#1 +RET + +no_colision: +ld l,h +ret + +TOCADO: + LD HL,#SPR2X + LD A,(#SPR1X) + CP (HL) + jp C,C1 + LD A,(HL) + ADD A,B ;alto del sprite1 + LD B,A + LD A,(#SPR1X) + SUB B + RET NC + jp COMPROBAR +C1: + ADD A,D ;alto sprite2 + LD D,A + LD A,(HL) + SUB D + RET NC +COMPROBAR: + INC HL + LD A,(#SPR1Y) + CP (HL) + jp C,C2 + LD A,(HL) + ADD A,C + LD C,A + LD A,(#SPR1Y) + SUB C + RET +C2: + ADD A,E + LD E,A + LD A,(HL) + SUB E + RET + +SPR1X: +.db 0 +SPR1Y: +.db 0 +SPR2X: +.db 0 +SPR2Y: +.db 0 diff --git a/lib/cpcrslib/cpc_DisableEnableFirmware.s b/lib/cpcrslib/cpc_DisableEnableFirmware.s new file mode 100644 index 0000000..00a8710 --- /dev/null +++ b/lib/cpcrslib/cpc_DisableEnableFirmware.s @@ -0,0 +1,28 @@ +.globl _cpc_DisableFirmware + +_cpc_DisableFirmware:: + DI + LD HL,(#0X0038) + LD (backup_fw),HL + LD HL,#0X0038 + LD (HL),#0XFB ;EI + INC HL + LD (HL),#0XC9 ;RET + EI + RET + +backup_fw: + .DW #0 + +.globl _cpc_EnableFirmware + +_cpc_EnableFirmware:: + DI + LD DE,(backup_fw) + LD HL,#0X0038 + LD (HL),E ;EI + INC HL + LD (HL),D ;RET + EI + RET + diff --git a/lib/cpcrslib/cpc_GetScrAddress.s b/lib/cpcrslib/cpc_GetScrAddress.s new file mode 100644 index 0000000..42b17f7 --- /dev/null +++ b/lib/cpcrslib/cpc_GetScrAddress.s @@ -0,0 +1,65 @@ +.globl _cpc_GetScrAddress + +_cpc_GetScrAddress:: + +; LD IX,#2 +; ADD IX,SP +; LD A,0 (IX) +; LD L,1 (IX) ;pantalla + + + LD HL,#2 + ADD HL,SP + LD A,(HL) + INC HL + LD L,(HL) + ;LD L,E + ;JP cpc_GetScrAddress0 + + +cpc_GetScrAddress0: ;en HL están las coordenadas + + ;LD A,H + LD (#inc_ancho+1),A + LD A,L + SRL A + SRL A + SRL A + ; A indica el bloque a multiplicar x &50 + LD D,A ;D + SLA A + SLA A + SLA A + SUB L + NEG + ; A indica el desplazamiento a multiplicar x &800 + LD E,A ;E + LD L,D + LD H,#0 + ADD HL,HL + LD BC,#bloques + ADD HL,BC + ;HL APUNTA AL BLOQUE BUSCADO + LD C,(HL) + INC HL + LD H,(HL) + LD L,C + ;HL TIENE EL VALOR DEL BLOQUE DE 8 BUSCADO + PUSH HL + LD D,#0 + LD HL,#sub_bloques + ADD HL,DE + LD A,(HL) + POP HL + ADD H + LD H,A +inc_ancho: + LD E,#0 + ADD HL,DE + RET + +bloques: +.DW #0XC000,#0XC050,#0XC0A0,#0XC0F0,#0XC140,#0XC190,#0XC1E0,#0XC230,#0XC280,#0XC2D0,#0XC320,#0XC370,#0XC3C0,#0XC410,#0XC460,#0XC4B0,#0XC500,#0XC550,#0XC5A0,#0XC5F0,#0XC640,#0XC690,#0XC6E0,#0XC730,#0XC780 +sub_bloques: +.DB #0X00,#0X08,#0X10,#0X18,#0X20,#0X28,#0X30,#0X38 + diff --git a/lib/cpcrslib/cpc_GetSp.s b/lib/cpcrslib/cpc_GetSp.s new file mode 100644 index 0000000..cb19efc --- /dev/null +++ b/lib/cpcrslib/cpc_GetSp.s @@ -0,0 +1,49 @@ +.globl _cpc_GetSp + +_cpc_GetSp:: + + LD IX,#2 + ADD IX,SP + LD E,0 (IX) + LD D,1 (IX) + LD A,3 (IX) + LD L,4 (IX) + LD H,5 (IX) + + + + LD (#loop_alto_2x_GetSp0+1),A + + + SUB #1 + CPL + LD (#salto_lineax_GetSp0+1),A ;comparten los 2 los mismos valores. + + LD A,2 (IX) + ;JP cpc_GetSp0 + +cpc_GetSp0:: + .DB #0XFD + LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + LD B,#7 +loop_alto_2x_GetSp0: + LD C,#0 +loop_ancho_2x_GetSp0: + LD A,(HL) + LD (DE),A + INC DE + INC HL + DEC C + JP NZ,loop_ancho_2x_GetSp0 + .DB #0XFD + DEC H + RET Z +salto_lineax_GetSp0: + LD C,#0XFF ;salto linea menos ancho + ADD HL,BC + JP NC,loop_alto_2x_GetSp0 ;sig_linea_2zz ;si no desborda va a la siguiente linea + LD BC,#0XC050 + ADD HL,BC + LD B,#7 ;sólo se daría una de cada 8 veces en un sprite + JP loop_alto_2x_GetSp0 + diff --git a/lib/cpcrslib/cpc_GphStr.s b/lib/cpcrslib/cpc_GphStr.s new file mode 100644 index 0000000..3f656fa --- /dev/null +++ b/lib/cpcrslib/cpc_GphStr.s @@ -0,0 +1,700 @@ +; ****************************************************** +; ** Librera de rutinas SDCC para Amstrad CPC ** +; ** Ral Simarro (Artaburu) - 2009, 2012 ** +; ****************************************************** + + + +cpc_GetScrAddress0: ;en HL estn las coordenadas + + ;LD A,H + LD (#inc_ancho+1),A + LD A,L + SRL A + SRL A + SRL A + ; A indica el bloque a multiplicar x &50 + LD D,A ;D + SLA A + SLA A + SLA A + SUB L + NEG + ; A indica el desplazamiento a multiplicar x &800 + LD E,A ;E + LD L,D + LD H,#0 + ADD HL,HL + LD BC,#bloques + ADD HL,BC + ;HL APUNTA AL BLOQUE BUSCADO + LD C,(HL) + INC HL + LD H,(HL) + LD L,C + ;HL TIENE EL VALOR DEL BLOQUE DE 8 BUSCADO + PUSH HL + LD D,#0 + LD HL,#sub_bloques + ADD HL,DE + LD A,(HL) + POP HL + ADD H + LD H,A +inc_ancho: + LD E,#0 + ADD HL,DE + RET + +bloques: +.DW #0XC000,#0XC050,#0XC0A0,#0XC0F0,#0XC140,#0XC190,#0XC1E0,#0XC230,#0XC280,#0XC2D0,#0XC320,#0XC370,#0XC3C0,#0XC410,#0XC460,#0XC4B0,#0XC500,#0XC550,#0XC5A0,#0XC5F0,#0XC640,#0XC690,#0XC6E0,#0XC730,#0XC780 +sub_bloques: +.DB #0X00,#0X08,#0X10,#0X18,#0X20,#0X28,#0X30,#0X38 + + + + +;************************************* +; GRAPHIC TEXT +;************************************* + +.globl _cpc_PrintGphStr2X + +_cpc_PrintGphStr2X:: +;preparacin datos impresin. El ancho y alto son fijos! + LD IX,#2 + ADD IX,SP + LD L,2 (IX) + LD H,3 (IX) ;DESTINO + LD E,0 (IX) + LD D,1 (IX) ;TEXTO ORIGEN + LD A,#1 + JP cpc_PrintGphStr0 + + + +.globl _cpc_PrintGphStrXY2X + +_cpc_PrintGphStrXY2X:: +;preparacin datos impresin. El ancho y alto son fijos! + LD IX,#2 + ADD IX,SP + LD L,3 (IX) + LD A,2 (IX) ;pantalla + CALL cpc_GetScrAddress0 + LD E,0 (IX) + LD D,1 (IX) ;texto origen + LD A,#1 + JP cpc_PrintGphStr0 + +.globl _cpc_PrintGphStrXY + +_cpc_PrintGphStrXY:: +;preparacin datos impresin. El ancho y alto son fijos! + LD IX,#2 + ADD IX,SP + LD L,3 (IX) + LD A,2 (IX) ;pantalla + CALL cpc_GetScrAddress0 + LD E,0 (IX) + LD D,1 (IX) ;texto origen + JP cpc_PrintGphStr0 + + +.globl _cpc_PrintGphStr + +_cpc_PrintGphStr:: +;preparacin datos impresin. El ancho y alto son fijos! + LD IX,#2 + ADD IX,SP + LD L,2 (IX) + LD H,3 (IX) ;DESTINO + ;LD (CPC_PRINTGPHSTR0+DIRECC_DESTINO0),HL + LD E,0 (IX) + LD D,1 (IX) ;TEXTO ORIGEN + ;JP cpc_PrintGphStr0 + +cpc_PrintGphStr0: + + ;DE destino + ;HL origen + ;ex de,hl + LD (#doble),A + ;trabajo previo: Para tener una lista de trabajos de impresin. No se interrumpe + ;la impresin en curso. + LD A,(#imprimiendo) + CP #1 + JP Z,add_elemento + LD (#direcc_destino),HL + EX DE,HL + CALL bucle_texto0 + +;antes de terminar, se mira si hay algo en cola. +bucle_cola_impresion: + LD A,(#elementos_cola) + OR A + JP Z,terminar_impresion + CALL leer_elemento + JP bucle_cola_impresion + + +terminar_impresion: + XOR A + LD (#imprimiendo),A + RET +entrar_cola_impresion: +;si se est imprimiendo se mete el valor en la cola + RET +add_elemento: + DI + LD IX,(#pos_cola) + LD 0 (IX),L + LD 1 (IX),H + LD 2 (IX),E + LD 3 (IX),D + INC IX + INC IX + INC IX + INC IX + LD (#pos_cola),IX + + LD HL,#elementos_cola + INC (HL) + ;Se aaden los valores hl y de + EI + RET +leer_elemento: + DI + LD IX,(#pos_cola) + LD L,0 (IX) + LD H,1 (IX) + LD E,2 (IX) + LD D,4 (IX) + DEC IX + DEC IX + DEC IX + DEC IX + LD (#pos_cola),IX + LD HL,#elementos_cola + DEC (HL) + EI + RET + +elementos_cola: + .DW #0 ; defw 0 +pos_cola: + .DW #cola_impresion ;defw cola_impresion + ;pos_escritura_cola defw cola_impresion +cola_impresion: ; defs 12 + .DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +bucle_texto0: + LD A,#1 + LD (imprimiendo),A + + LD A,(first_char) + LD B,A ;resto 48 para saber el nmero del caracter (En ASCII 0=48) + + LD A,(HL) + OR A ;CP 0 + RET Z + SUB B + LD BC,(#cpc_Chars) ;apunto a la primera letra + PUSH HL + + LD L,A ;en A tengo la letra que sera + LD H,#0 + ADD HL,HL + ADD HL,HL + ADD HL,HL ;x8 porque cada letra son 8 bytes + ADD HL,BC ;ahora HL apunta a los datos de la letra correspondiente + CALL escribe_letra + LD A,(doble) + CP #1 +; ANTES DE IMPRIMIR SE CHEQUEA SI ES DE ALTURA EL DOBLE Y SE ACTA EN CONSECUENCIA + CALL Z, doblar_letra + LD HL,(#direcc_destino) + LD A,(doble) + CP #1 + ;alto + JR Z,cont_doble + LD DE,#letra_decodificada + .DB #0xfD + LD H,#8 ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + JR cont_tot + + +cont_doble: + LD DE,#letra_decodificada_tmp + .DB #0xfD + LD H,#16 ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + +cont_tot: + CALL cpc_PutSp0 + LD HL,(#direcc_destino) + INC HL + INC HL + LD (#direcc_destino),HL + POP HL + INC HL + JP bucle_texto0 + + +doble: + .DB #0 +imprimiendo: + .DB #0 +direcc_destino: + .DW #0 + + +cpc_PutSp0: +; .DB #0xfD +; LD H,16 ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + LD B,#7 + LD C,B +loop_alto_2: + +loop_ancho_2: + EX DE,HL + LDI + LDI + .DB #0XFD + DEC H + RET Z + EX DE,HL +salto_linea: + LD C,#0XFE ;&07F6 ;SALTO LINEA MENOS ANCHO + ADD HL,BC + JP NC,loop_alto_2 ;SIG_LINEA_2ZZ ;SI NO DESBORDA VA A LA SIGUIENTE LINEA + LD BC,#0XC050 + ADD HL,BC + LD B,#7 ;SLO SE DARA UNA DE CADA 8 VECES EN UN SPRITE + JP loop_alto_2 + + + + +doblar_letra: + LD HL,#letra_decodificada + LD DE,#letra_decodificada_tmp + LD B,#8 +buc_doblar_letra: + LD A,(HL) + INC HL + LD (DE),A + INC DE + INC DE + LD (DE),A + DEC DE + LD A,(HL) + INC HL + LD (DE),A + INC DE + INC DE + LD (DE),A + INC DE + DJNZ buc_doblar_letra + RET + + +escribe_letra: ; Code by Kevin Thacker + PUSH DE + LD IY,#letra_decodificada + LD B,#8 +bucle_alto_letra: + PUSH BC + PUSH HL + LD E,(HL) + CALL op_colores + LD (IY),D + INC IY + CALL op_colores + LD (IY),D + INC IY + POP HL + INC HL + POP BC + DJNZ bucle_alto_letra + POP DE + RET + +op_colores: + ld d,#0 ;; initial byte at end will be result of 2 pixels combined + CALL op_colores_pixel ;; do pixel 0 + RLC D + CALL op_colores_pixel + RRC D + RET + +;; follow through to do pixel 1 + +op_colores_pixel: + ;; shift out pixel into bits 0 and 1 (source) + RLC E + RLC E + ;; isolate + LD A,E + AND #0X3 + LD HL,#colores_b0 + ADD A,L + LD L,A + LD A,H + ADC A,#0 + LD H,A + ;; READ IT AND COMBINE WITH PIXEL SO FAR + LD A,D + OR (HL) + LD D,A + RET + + +.globl _cpc_SetInkGphStr + +_cpc_SetInkGphStr:: +;preparacin datos impresin. El ancho y alto son fijos! + LD IX,#2 + ADD IX,SP + + ;LD A,H + ;LD C,L + LD A,1 (IX) ;VALOR + LD C,0 (IX) ;COLOR + + LD HL,#colores_b0 + LD B,#0 + ADD HL,BC + LD (HL),A + RET + + + + + +.globl _cpc_PrintGphStrXYM1 + +_cpc_PrintGphStrXYM1:: +;preparacin datos impresin. El ancho y alto son fijos! + LD IX,#2 + ADD IX,SP + LD L,3 (IX) + LD A,2 (IX) ;pantalla + CALL cpc_GetScrAddress0 + LD E,0 (IX) + LD D,1 (IX) ;texto origen + XOR A + JP cpc_PrintGphStr0M1 + + +.globl _cpc_PrintGphStrXYM12X + +_cpc_PrintGphStrXYM12X:: +;preparacin datos impresin. El ancho y alto son fijos! + LD IX,#2 + ADD IX,SP + LD L,3 (IX) + LD A,2 (IX) ;pantalla + CALL cpc_GetScrAddress0 + LD E,0 (IX) + LD D,1 (IX) ;texto origen + LD A,#1 + JP cpc_PrintGphStr0M1 + + + + +.globl _cpc_PrintGphStrM12X + +_cpc_PrintGphStrM12X:: + LD IX,#2 + ADD IX,SP + LD L,2 (IX) + LD H,3 (IX) ;DESTINO + LD E,0 (IX) + LD D,1 (IX) ;TEXTO ORIGEN + LD A,#1 + + JP cpc_PrintGphStr0M1 + + + +.globl _cpc_PrintGphStrM1 + +_cpc_PrintGphStrM1:: +;preparacin datos impresin. El ancho y alto son fijos! + + LD IX,#2 + ADD IX,SP + LD L,2 (IX) + LD H,3 (IX) ;DESTINO + LD E,0 (IX) + LD D,1 (IX) ;TEXTO ORIGEN + XOR A + + ;JP cpc_PrintGphStr0M1 + +cpc_PrintGphStr0M1: + ;DE destino + ;HL origen + ;ex de,hl + LD (#dobleM1),A + ;trabajo previo: Para tener una lista de trabajos de impresin. No se interrumpe + ;la impresin en curso. + LD A,(#imprimiendo) + CP #1 + JP Z,add_elemento + LD (#direcc_destino),HL + EX DE,HL + CALL bucle_texto0M1 +;antes de terminar, se mira si hay algo en cola. +bucle_cola_impresionM1: + LD A,(#elementos_cola) + OR A + JP Z,terminar_impresion + CALL leer_elemento + JP bucle_cola_impresionM1 + + + + + +bucle_texto0M1: + LD A,#1 + LD (#imprimiendo),A + + LD A,(#first_char) + LD B,A ;resto 48 para saber el nmero del caracter (En ASCII 0=48) + LD A,(HL) + OR A ;CP 0 + RET Z + SUB B + LD BC,(#cpc_Chars) ;apunto a la primera letra + PUSH HL + LD L,A ;en A tengo la letra que sera + LD H,#0 + ADD HL,HL + ADD HL,HL + ADD HL,HL ;x8 porque cada letra son 8 bytes + ADD HL,BC ;ahora HL apunta a los datos de la letra correspondiente + CALL escribe_letraM1 + LD A,(dobleM1) + CP #1 + ; ANTES DE IMPRIMIR SE CHEQUEA SI ES DE ALTURA EL DOBLE Y SE ACTA EN CONSECUENCIA + CALL Z, doblar_letraM1 + LD HL,(direcc_destino) + LD A,(dobleM1) + CP #1 + ;alto + JR Z,cont_dobleM1 + LD DE,#letra_decodificada + .DB #0xfD + LD H,#8 ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + JR cont_totM1 + + +cont_dobleM1: + LD DE,#letra_decodificada_tmp + .DB #0XFD + LD H,#16 ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE +cont_totM1: + CALL cpc_PutSp0M1 + LD HL,(#direcc_destino) + INC HL + LD (#direcc_destino),HL + POP HL + INC HL + JP bucle_texto0M1 + +dobleM1: + .DB #0 +;.imprimiendo defb 0 +;.direcc_destino defw 0 + +doblar_letraM1: + LD HL,#letra_decodificada + LD DE,#letra_decodificada_tmp + LD B,#8 +buc_doblar_letraM1: + LD A,(HL) + INC HL + LD (DE),A + INC DE + LD (DE),A + INC DE + DJNZ buc_doblar_letraM1 + RET + + +cpc_PutSp0M1: + ; defb #0xfD + ; LD H,8 ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + LD B,#7 + LD C,B +loop_alto_2M1: +loop_ancho_2M1: + EX DE,HL + LDI + .DB #0XFD + DEC H + RET Z + EX DE,HL +salto_lineaM1: + LD C,#0XFF ;#0x07f6 ;salto linea menos ancho + ADD HL,BC + JP NC,loop_alto_2M1 ;sig_linea_2zz ;si no desborda va a la siguiente linea + LD BC,#0XC050 + ADD HL,BC + LD B,#7 ;slo se dara una de cada 8 veces en un sprite + JP loop_alto_2M1 + + + +escribe_letraM1: + LD IY,#letra_decodificada + LD B,#8 + LD IX,#byte_tmp +bucle_altoM1: + PUSH BC + PUSH HL + + LD A,(HL) + LD HL,#dato + LD (HL),A + ;me deja en ix los valores convertidos + ;HL tiene la direccin origen de los datos de la letra + ;LD DE,letra ;el destino es la posicin de decodificacin de la letra + ;Se analiza el byte por parejas de bits para saber el color de cada pixel. + LD (IX),#0 ;reset el byte + LD B,#4 ;son 4 pixels por byte. Los recorro en un bucle y miro qu color tiene cada byte. +bucle_coloresM1: + ;roto el byte en (HL) + PUSH HL + CALL op_colores_m1 ;voy a ver qu color es el byte. tengo un mximo de 4 colores posibles en modo 0. + POP HL + SRL (HL) + SRL (HL) ;voy rotando el byte para mirar los bits por pares. + DJNZ bucle_coloresM1 + LD A,(IX) + LD (IY),A + INC IY + POP HL + INC HL + POP BC + DJNZ bucle_altoM1 + RET + + +;.rutina +;HL tiene la direccin origen de los datos de la letra + +;Se analiza el byte por parejas de bits para saber el color de cada pixel. +;ld ix,byte_tmp +;ld (ix+0),0 + +;LD B,4 ;son 4 pixels por byte. Los recorro en un bucle y miro qu color tiene cada byte. +;.bucle_colores +;roto el byte en (HL) +;push hl +;call op_colores_m1 ;voy a ver qu color es el byte. tengo un mximo de 4 colores posibles en modo 0. +;pop hl +;sla (HL) +;sla (HL) ;voy rotando el byte para mirar los bits por pares. + +;djnz bucle_colores + +;ret +op_colores_m1: ;rutina en modo 1 + ;mira el color del bit a pintar + LD A,#3 ;hay 4 colores posibles. Me quedo con los 2 primeros bits + AND (HL) + ; EN A tengo el nmero de bytes a sumar!! + LD HL,#colores_m1 + LD E,A + LD D,#0 + ADD HL,DE + LD C,(HL) + ;EN C EST EL BYTE DEL COLOR + ;LD A,4 + ;SUB B + LD A,B + DEC A + OR A ;CP 0 + JP Z,_sin_rotar +rotando: + SRL C + DEC A + JP NZ, rotando +_sin_rotar: + LD A,C + OR (IX) + LD (IX),A + ;INC IX + RET + + +.globl _cpc_SetInkGphStrM1 + +_cpc_SetInkGphStrM1:: + LD IX,#2 + ADD IX,SP + LD A,1 (IX) ;VALOR + LD C,0 (IX) ;COLOR + LD HL,#colores_cambM1 + LD B,#0 + ADD HL,BC + LD (HL),A + RET + + + +colores_cambM1: +colores_m1: + .DB #0b00000000,#0b10001000,#0b10000000,#0b00001000 + +;defb @00000000, @01010100, @00010000, @00000101 ;@00000001, @00000101, @00010101, @00000000 + + + +;DEFC direcc_destino0_m1 = direcc_destino +;DEFC colores_cambM1 = colores_m1 + + +.globl _cpc_SetFont + +_cpc_SetFont:: + ld ix, #2 + add ix, sp + ld a, 0(ix) + ld (#first_char), a + ld l, 1(ix) + ld h, 2(ix) + ld (#cpc_Chars), hl + ret + +dato: + .DB #0b00011011 ;aqu dejo temporalmente el byte a tratar + +byte_tmp: + .DB #0 + .DB #0 + .DB #0 ;defs 3 +colores_b0: ;defino los 4 colores posibles para el byte. Los colores pueden ser cualesquiera. + ;Pero se tienen que poner bien, en la posicin que le corresponda. + .DB #0b00001010,#0b00100000,#0b10100000,#0b00101000 + ;.DB #0b00000000, #0b01010100, #0b00010000, #0b00000101 ;#0b00000001, #0b00000101, #0b00010101, #0b00000000 + +letra_decodificada: ;. defs 16 ;16 ;uso este espacio para guardar la letra que se decodifica + .DB #0,#0,#0,#0,#0,#0,#0,#0 + .DB #0,#0,#0,#0,#0,#0,#0,#0 +letra_decodificada_tmp: ;defs 32 ;16 ;uso este espacio para guardar la letra que se decodifica para tamao doble altura + .DB #0,#0,#0,#0,#0,#0,#0,#0 + .DB #0,#0,#0,#0,#0,#0,#0,#0 + .DB #0,#0,#0,#0,#0,#0,#0,#0 + .DB #0,#0,#0,#0,#0,#0,#0,#0 + + +first_char: + .DB #0 ;first defined char number (ASCII) + +cpc_Chars: ;cpc_Chars codificadas... cada pixel se define con 2 bits que definen el color. + .DW #0 + diff --git a/lib/cpcrslib/cpc_Keyboard.s b/lib/cpcrslib/cpc_Keyboard.s new file mode 100644 index 0000000..4b7e623 --- /dev/null +++ b/lib/cpcrslib/cpc_Keyboard.s @@ -0,0 +1,348 @@ +; ****************************************************** +; ** Librera de rutinas SDCC para Amstrad CPC ** +; ** Ral Simarro (Artaburu) - 2009, 2012 ** +; ****************************************************** + +;************************************* +; KEYBOARD +;************************************* + + +.globl _cpc_AnyKeyPressed + + +_cpc_AnyKeyPressed:: + call hacer_tiempo + call hacer_tiempo + call hacer_tiempo + + + + LD A,#40 +bucle_deteccion_tecla: + PUSH AF + CALL cpc_TestKeyboard ;en A vuelve los valores de la linea + OR A + JP NZ, tecla_pulsada ; retorna si no se ha pulsado ninguna tecla + POP AF + INC A + CP #0x4a + JP NZ, bucle_deteccion_tecla + LD HL,#0 + + RET + +tecla_pulsada: + POP AF + LD HL,#1 + RET +t_pulsada: + POP AF + JP _cpc_AnyKeyPressed + +hacer_tiempo: + LD A,#254 +bucle_previo_deteccion_tecla: + PUSH AF + POP AF + dec A + Jr nZ, bucle_previo_deteccion_tecla + ret + + + +.globl _cpc_AssignKey + +_cpc_AssignKey:: + + LD HL,#2 + ADD HL,SP + LD E,(HL) ;E-> numero tecla + INC HL + ;INC HL + LD A,(HL) ;linea, byte + INC HL + LD B,(HL) ;DE tiene el valor de la tecla a escribir en la tabla + ; En A se tiene el valor de la tecla seleccionada a comprobar [0..11] + ;___________________________________________________________________ + ; ;En A viene la tecla a redefinir (0..11) + SLA E + LD D,#0 + LD HL, #tabla_teclas + ADD HL,DE ;Nos colocamos en la tecla a redefinir y la borramos + LD (HL),#0XFF + INC HL + LD (HL),#0XFF + DEC HL + PUSH HL + ;call ejecutar_deteccion_teclado ;A tiene el valor del teclado + ; A tiene el byte (<>0) + ; B tiene la linea + ;guardo linea y byte + POP HL + LD (HL),A ;byte + INC HL + LD (HL),B + RET + + +.globl _cpc_TestKey + +_cpc_TestKey:: + + LD HL,#2 + ADD HL,SP + LD L,(HL) ; En A se tiene el valor de la tecla seleccionada a comprobar [0..11] + SLA L + INC L + LD H,#0 + LD DE,#tabla_teclas + ADD HL,DE + LD A,(HL) + CALL cpc_TestKeyboard ; esta rutina lee la lnea del teclado correspondiente + DEC HL ; pero slo nos interesa una de las teclas. + and (HL) ;para filtrar por el bit de la tecla (puede haber varias pulsadas) + CP (HL) ;comprueba si el byte coincide + LD H,#0 + JP Z,pulsado + LD L,H + RET +pulsado: + LD L,#1 + RET + + + + + +.globl _cpc_RedefineKey + +_cpc_RedefineKey:: + + LD HL,#2 + ADD HL,SP + LD L,(HL) + SLA L + LD H,#0 + LD DE,#tabla_teclas + ADD HL,DE ;Nos colocamos en la tecla a redefinir + LD (HL),#0XFF ; y la borramos + INC HL + LD (HL),#0XFF + DEC HL + PUSH HL + CALL ejecutar_deteccion_teclado ;A tiene el valor del teclado + LD A,D + ; A tiene el byte (<>0) + ; B tiene la linea + ;guardo linea y byte + POP HL ;recupera posicin leda + LD A,(linea) + LD (HL),A ;byte + INC HL + LD A,(bte) + LD (HL),A + RET + + +ejecutar_deteccion_teclado: + LD A,#0x40 +bucle_deteccion_tecla1: + PUSH AF + LD (bte),A + CALL cpc_TestKeyboard ;en A vuelve los valores de la linea + OR A + JR NZ, tecla_pulsada1 ; retorna si no se ha pulsado ninguna tecla + POP AF + INC A + CP #0x4A + JR NZ, bucle_deteccion_tecla1 + JR ejecutar_deteccion_teclado + +tecla_pulsada1: + LD (linea),A + POP AF + CALL comprobar_si_tecla_usada + RET NC + JR bucle_deteccion_tecla1 + +comprobar_si_tecla_usada: ; A tiene byte, B linea + LD B,#12 ;numero mximo de tecla redefinibles + LD IX,#tabla_teclas + LD C,(IX) +bucle_bd_teclas: ;comprobar byte + LD A,(linea) + LD C,(IX) + CP (IX) + JR Z, comprobar_linea + INC IX + INC IX + DJNZ bucle_bd_teclas + SCF + CCF + RET ; si vuelve despus de comprobar, que sea NZ +comprobar_linea: ;si el byte es el mismo, mira la linea + LD A,(bte) + CP 1 (IX) ; esto es (ix+1) + JR Z, tecla_detectada ; Vuelve con Z si coincide el byte y la linea + INC IX + INC IX + DJNZ bucle_bd_teclas + SCF + CCF + RET ; si vuelve despus de comprobar, que sea NZ +tecla_detectada: + SCF + RET + + +.globl _cpc_DeleteKeys + +_cpc_DeleteKeys:: ;borra la tabla de las teclas para poder redefinirlas todas + LD HL,#tabla_teclas + LD DE,#tabla_teclas+#1 + LD BC, #24 + LD (HL),#0xFF + LDIR + RET + + +.globl _cpc_TestKeyF + +_cpc_TestKeyF:: + LD HL,#2 + ADD HL,SP + LD L,(HL) + SLA L + INC L + LD H,#0 + LD DE,#tabla_teclas + ADD HL,DE + LD A,(HL) + SUB #0X40 + EX DE,HL + LD HL,#keymap ;; LEE LA LNEA BUSCADA DEL KEYMAP + LD C,A + LD B,#0 + ADD HL,BC + LD A,(HL) + EX DE,HL + DEC HL ; PERO SLO NOS INTERESA UNA DE LAS TECLAS. + AND (HL) ;PARA FILTRAR POR EL BIT DE LA TECLA (PUEDE HABER VARIAS PULSADAS) + CP (HL) ;COMPRUEBA SI EL BYTE COINCIDE + LD H,#0 + JP NZ,#pulsado_cpc_TestKeyF + LD L,H + RET +pulsado_cpc_TestKeyF: + LD L,#1 + RET + + +.globl _cpc_ScanKeyboard + +_cpc_ScanKeyboard:: + + DI ;1 #0X#0X%%#0X#0X C P C VERSION #0X#0X%%#0X#0X FROM CPCWIKI + LD HL,#keymap ;3 + LD BC,#0XF782 ;3 + OUT (C),C ;4 + LD BC,#0XF40E ;3 + LD E,B ;1 + OUT (C),C ;4 + LD BC,#0XF6C0 ;3 + LD D,B ;1 + OUT (C),C ;4 + LD C,#0 ;2 + OUT (C),C ;4 + LD BC,#0XF792 ;3 + OUT (C),C ;4 + LD A,#0X40 ;2 + LD C,#0X4A ;2 44 +loop_cpc_scankeyboard: + LD B,D ;1 + OUT (C),A ;4 SELECT LINE + LD B,E ;1 + INI ;5 READ BITS AND WRITE INTO KEYMAP + INC A ;1 + CP C ;1 + JR C,loop_cpc_scankeyboard ;2/3 9*16+1*15=159 + LD BC,#0XF782 ;3 + OUT (C),C ;4 + EI ;1 8 =211 MICROSECONDS + RET + + + +cpc_TestKeyboard:: ;Tomado de las rutinas bsicas que aparecen + ;en los documentos de Kevin Thacker + + DI + LD BC, #0XF40E + OUT (C), C + LD BC, #0XF6C0 + OUT (C), C + .DB #0XED,#0X71 ; OUT (C),0 + LD BC, #0XF792 + OUT (C), C + DEC B + OUT (C), A + LD B, #0XF4 + IN A, (C) + LD BC, #0XF782 + OUT (C), C + DEC B + .DB #0XED,#0X71 ; OUT (C),0 + CPL + EI + RET + +linea: + .DB #0 +bte: + .DB #0 + +keymap: + .DB #0 + .DB #0 + .DB #0 + .DB #0 + .DB #0 + .DB #0 + .DB #0 + .DB #0 + .DB #0 + .DB #0 + +tecla_0: .DW #0x0204 +;teclado_usable ; teclas del cursor, cada tecla est definida por su bit y su lnea. +tabla_teclas: +tecla_0_x: .DW #0xffff ; bit 0, lnea 2 +tecla_1_x: .DW #0xffff ; bit 1, lnea 1 +tecla_2_x: .DW #0xffff ; bit 0, lnea 1 +tecla_3_x: .DW #0xffff ; bit 0, lnea 4 +tecla_4_x: .DW #0xffff ; bit 0, lnea 2 +tecla_5_x: .DW #0xffff ; bit 1, lnea 1 +tecla_6_x: .DW #0xffff ; bit 0, lnea 1 +tecla_7_x: .DW #0xffff ; bit 0, lnea 4 +tecla_8_x: .DW #0xffff ; bit 0, lnea 4 +tecla_9_x: .DW #0xffff ; bit 0, lnea 4 +tecla_10_x: .DW #0xffff ; bit 0, lnea 4 +tecla_11_x: .DW #0xffff ; bit 0, lnea 4 +tecla_12_x: .DW #0xffff ; bit 0, lnea 4 +tecla_13_x: .DW #0xffff ; bit 0, lnea 4 +tecla_14_x: .DW #0xffff ; bit 0, lnea 4 +tecla_15_x: .DW #0xffff ; bit 0, lnea 4 +; For increasing keys available just increase this word table +.DB #0 + + + + + + + + + + + diff --git a/lib/cpcrslib/cpc_PrintStr.s b/lib/cpcrslib/cpc_PrintStr.s new file mode 100644 index 0000000..28e713a --- /dev/null +++ b/lib/cpcrslib/cpc_PrintStr.s @@ -0,0 +1,27 @@ +.globl _cpc_PrintStr + +_cpc_PrintStr:: + LD IX,#2 + ADD IX,SP + LD l,0 (IX) + LD h,1 (IX) ;TEXTO ORIGEN + +; LD HL,#2 + ; ADD HL,SP +; LD E,(HL) +; INC HL +; LD D,(HL) +; EX DE,HL +bucle_imp_cadena: + LD A,(HL) + OR A + JR Z,salir_bucle_imp_cadena + CALL #0XBB5A + INC HL + JR bucle_imp_cadena +salir_bucle_imp_cadena: + LD A,#0X0D ; PARA TERMINAR HACE UN SALTO DE LÍNEA + CALL #0XBB5A + LD A,#0X0A + JP 0XBB5A + diff --git a/lib/cpcrslib/cpc_PutMaskSp.s b/lib/cpcrslib/cpc_PutMaskSp.s new file mode 100644 index 0000000..e9683e4 --- /dev/null +++ b/lib/cpcrslib/cpc_PutMaskSp.s @@ -0,0 +1,79 @@ +;void cpc_PutMaskSprite(int *sprite, int *posicion); +;void cpc_PutMaskSp(int *sprite, char alto, char ancho, int *posicion); +.globl _cpc_PutMaskSp + +_cpc_PutMaskSp:: ; dibujar en pantalla el sprite + ; Entradas bc-> Alto Ancho + ; de-> origen + ; hl-> destino + ; Se alteran hl, bc, de, af + + LD IX,#2 + ADD IX,SP + LD L,4 (IX) + LD H,5 (IX) + LD A,3 (IX) + LD E,0 (IX) + LD D,1 (IX) + ld (#loop_alto_2m_PutMaskSp0+#1),a ;actualizo rutina de captura + SUB #1 + CPL + LD (#salto_lineam_PutMaskSp0+#1),A ;comparten los 2 los mismos valores. + ld A,2(IX) + ;JP cpc_PutMaskSp0 + +cpc_PutMaskSp0: + .DB #0XFD + LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + LD B,#7 +loop_alto_2m_PutMaskSp0: + LD C,#4 + EX DE,HL +loop_ancho_2m_PutMaskSp0: + LD A,(DE) ;LEO EL BYTE DEL FONDO + AND (HL) ;LO ENMASCARO + INC HL + OR (HL) ;LO ENMASCARO + LD (DE),A ;ACTUALIZO EL FONDO + INC DE + INC HL + DEC C + JP NZ,loop_ancho_2m_PutMaskSp0 + .DB #0XFD + DEC H + RET Z + EX DE,HL +salto_lineam_PutMaskSp0: + LD C,#0XFF + ADD HL,BC + JP nc,loop_alto_2m_PutMaskSp0 + LD BC,#0XC050 + ADD HL,BC + LD B,#7 + JP loop_alto_2m_PutMaskSp0 + +.globl _cpc_PutMaskSprite + +_cpc_PutMaskSprite:: ; dibujar en pantalla el sprite + ; Entradas bc-> Alto Ancho + ; de-> origen + ; hl-> destino + ; Se alteran hl, bc, de, af + + POP AF + POP HL + POP DE + PUSH AF + LD A,(HL) ;ANCHO + INC HL + ld (#loop_alto_2m_PutMaskSp0+#1),a ;ACTUALIZO RUTINA DE CAPTURA + ;LD (ANCHOT+1),A ;ACTUALIZO RUTINA DE DIBUJO + SUB #1 + CPL + LD (#salto_lineam_PutMaskSp0+#1),A ;COMPARTEN LOS 2 LOS MISMOS VALORES. + LD A,(HL) ;ALTO + INC HL + EX DE,HL + jp cpc_PutMaskSp0 + + diff --git a/lib/cpcrslib/cpc_PutMaskSp2x8.s b/lib/cpcrslib/cpc_PutMaskSp2x8.s new file mode 100644 index 0000000..ac85f0e --- /dev/null +++ b/lib/cpcrslib/cpc_PutMaskSp2x8.s @@ -0,0 +1,45 @@ +.globl _cpc_PutMaskSp2x8 +; imprime un sprite de 8x8 en modo 1 +; El formato del sprite es el siguiente por cada línea: +; defb byte1,byte2,byte3,byte4 +; siendo byte1 y byte3 son las máscaras de los bytes 2 y 4 +; se recibe de entrada el sprite y la posición. +_cpc_PutMaskSp2x8:: + LD IX,#2 + ADD IX,SP + LD L,2 (IX) + LD H,3 (IX) + LD E,0 (IX) + LD D,1 (IX) + .DB #0XFD + LD H,#8 ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + LD B,#7 +loop_alto_mask_2x8: + EX DE,HL + LD A,(DE) ;leo el byte del fondo + AND (HL) ;lo enmascaro + INC HL + OR (HL) ;lo enmascaro + LD (DE),A ;actualizo el fondo + INC DE + INC HL + ;COMO SOLO SON 2 BYTES, es más rápido y económico desplegar la rutina + LD A,(DE) + AND (HL) + INC HL + OR (HL) + LD (DE),A + INC DE + INC HL + .DB #0XFD + DEC H + RET Z + EX DE,HL + LD C,#0XFE + ADD HL,BC + JP NC,loop_alto_mask_2x8 + LD BC,#0XC050 + ADD HL,BC + LD B,#7 + JP loop_alto_mask_2x8 + diff --git a/lib/cpcrslib/cpc_PutMaskSp4x16.s b/lib/cpcrslib/cpc_PutMaskSp4x16.s new file mode 100644 index 0000000..4fbbd61 --- /dev/null +++ b/lib/cpcrslib/cpc_PutMaskSp4x16.s @@ -0,0 +1,56 @@ +.globl _cpc_PutMaskSp4x16 + +_cpc_PutMaskSp4x16:: + + LD IX,#2 + ADD IX,SP + LD L,2 (IX) + LD H,3 (IX) + LD E,0 (IX) + LD D,1 (IX) + .DB #0XFD + LD H,#16 + LD B,#7 +loop_alto_mask_4x16: + EX DE,HL + LD A,(DE) ;leo el byte del fondo + AND (HL) ;lo enmascaro + INC HL + OR (HL) ;lo enmascaro + LD (DE),A ;actualizo el fondo + INC DE + INC HL + ;COMO SOLO SON 4 BYTES, es más rápido y económico desplegar la rutina + LD A,(DE) ;leo el byte del fondo + AND (HL) ;lo enmascaro + INC HL + OR (HL) ;lo enmascaro + LD (DE),A ;actualizo el fondo + INC DE + INC HL + LD A,(DE) ;leo el byte del fondo + AND (HL) ;lo enmascaro + INC HL + OR (HL) ;lo enmascaro + LD (DE),A ;actualizo el fondo + INC DE + INC HL + LD A,(DE) ;leo el byte del fondo + AND (HL) ;lo enmascaro + INC HL + OR (HL) ;lo enmascaro + LD (DE),A ;actualizo el fondo + INC DE + INC HL + .DB #0XFD + DEC H + RET Z + EX DE,HL + LD C,#0XFC + ADD HL,BC + JP NC,loop_alto_mask_4x16 + LD BC,#0XC050 + ADD HL,BC + LD B,#7 + JP loop_alto_mask_4x16 + diff --git a/lib/cpcrslib/cpc_PutSp.s b/lib/cpcrslib/cpc_PutSp.s new file mode 100644 index 0000000..0ddbf10 --- /dev/null +++ b/lib/cpcrslib/cpc_PutSp.s @@ -0,0 +1,54 @@ +.globl _cpc_PutSp + +_cpc_PutSp:: ; dibujar en pantalla el sprite + ; Entradas bc-> Alto Ancho + ; de-> origen + ; hl-> destino + ; Se alteran hl, bc, de, af + + LD IX,#2 + ADD IX,SP + LD E,0 (IX) + LD D,1 (IX) + LD A,3 (IX) + LD L,4 (IX) + LD H,5 (IX) + + LD (#ancho0+1),A ;actualizo rutina de captura + ;ld (anchot+1),a ;actualizo rutina de dibujo + SUB #1 + CPL + LD (#suma_siguiente_linea0+1),A ;COMPARTEN LOS 2 LOS MISMOS VALORES. + + LD A,2 (IX) + ;JP cpc_putsp0 + +pc_PutSp0: + .DB #0XFD + LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + LD B,#7 +ancho0: +loop_alto_2_pc_PutSp0: + LD C,#4 +loop_ancho_2_pc_PutSp0: + LD A,(DE) + LD (HL),A + INC DE + INC HL + DEC C + JP NZ,loop_ancho_2_pc_PutSp0 + .DB #0XFD + DEC H + RET Z + +suma_siguiente_linea0: +salto_linea_pc_PutSp0: + LD C,#0XFF ;&07F6 ;SALTO LINEA MENOS ANCHO + ADD HL,BC + JP nc,loop_alto_2_pc_PutSp0 ;sig_linea_2zz ;si no desborda va a la siguiente linea + LD BC,#0XC050 + + ADD HL,BC + LD B,#7 ;SÓLO SE DARÍA UNA DE CADA 8 VECES EN UN SPRITE + JP loop_alto_2_pc_PutSp0 + diff --git a/lib/cpcrslib/cpc_PutSp2x14.s b/lib/cpcrslib/cpc_PutSp2x14.s new file mode 100644 index 0000000..241d66b --- /dev/null +++ b/lib/cpcrslib/cpc_PutSp2x14.s @@ -0,0 +1,50 @@ +.globl _cpc_PutSp4x14 + +_cpc_PutSp4x14:: ; dibujar en pantalla el sprite + ; Entradas bc-> Alto Ancho + ; de-> origen + ; hl-> destino + ; Se alteran hl, bc, de, af + + LD IX,#2 + ADD IX,SP + LD e,0 (IX) + LD d,1 (IX) ;sprite + LD l,2 (IX) + LD h,3 (IX) ;address + ld A,#14 + +pc_PutSp0X: + .DB #0XFD + LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + LD B,#7 +ancho0X: +loop_alto_2_pc_PutSp0X: + LD C,#4 +loop_ancho_2_pc_PutSp0X: + EX DE,HL + LDI + LDI + LDI + LDI + EX DE,HL + ;LD A,(DE) + ;LD (HL),A + ;INC DE + ;INC HL + ;DEC C + ;JP NZ,loop_ancho_2_pc_PutSp0X + .DB #0XFD + DEC H + RET Z + +suma_siguiente_linea0X: +salto_linea_pc_PutSp0X: + LD C,#0XFC ;&07F6 ;SALTO LINEA MENOS ANCHO + ADD HL,BC + JP nc,loop_alto_2_pc_PutSp0X ;sig_linea_2zz ;si no desborda va a la siguiente linea + LD BC,#0XC050 + ADD HL,BC + LD B,#7 ;SÓLO SE DARÍA UNA DE CADA 8 VECES EN UN SPRITE + JP loop_alto_2_pc_PutSp0X + diff --git a/lib/cpcrslib/cpc_PutSpTr.s b/lib/cpcrslib/cpc_PutSpTr.s new file mode 100644 index 0000000..e1d24fa --- /dev/null +++ b/lib/cpcrslib/cpc_PutSpTr.s @@ -0,0 +1,75 @@ +.globl _cpc_PutSpTr + +_cpc_PutSpTr:: ; dibujar en pantalla el sprite + ; Entradas bc-> Alto Ancho + ; de-> origen + ; hl-> destino + ; Se alteran hl, bc, de, af + LD IX,#2 + ADD IX,SP + LD E,0 (IX) + LD D,1 (IX) + LD A,4 (IX) + LD L,6 (IX) + LD H,7 (IX) + + + LD (#anchot+1),A ;actualizo rutina de dibujo + SUB #1 + CPL + LD (#suma_siguiente_lineat+1),A ;comparten los 2 los mismos valores. + + LD A,2 (IX) + ;JP cpc_PutSpTr0 + +cpc_PutSpTr0: + .DB #0XFD + LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE +anchot: +loop_alto_2t: + LD B,#0 +loop_ancho_2t: + LD A,(DE) + AND #0XAA + JP Z,sig_pixn_der_2 + LD C,A ;B es el único registro libre + LD A,(HL) ;pixel actual donde pinto + AND #0X55 + OR C + LD (HL),A ;y lo pone en pantalla +sig_pixn_der_2: + LD A,(DE) ;pixel del sprite + AND #0X55 + JP Z,pon_buffer_der_2 + LD C,A ;B es el único registro libre + LD A,(HL) ;PIXEL ACTUAL DONDE PINTO + AND #0XAA + OR C + LD (HL),A +pon_buffer_der_2: + INC DE + INC HL + DEC B + JP NZ,loop_ancho_2t + .DB #0XFD + DEC H + RET Z +suma_siguiente_lineat: +salto_lineat: + LD BC,#0X07FF ;&07f6 ;salto linea menos ancho + ADD HL,BC + JP NC,loop_alto_2t ;sig_linea_2zz ;si no desborda va a la siguiente linea + LD BC,#0XC050 + ADD HL,BC + ;ld b,7 ;sólo se daría una de cada 8 veces en un sprite + JP loop_alto_2t + + LD A,H + ADD #0X08 + LD H,A + SUB #0XC0 + JP NC,loop_alto_2t ;sig_linea_2 + LD BC,#0XC050 + ADD HL,BC + JP loop_alto_2t + diff --git a/lib/cpcrslib/cpc_PutSpXOR.s b/lib/cpcrslib/cpc_PutSpXOR.s new file mode 100644 index 0000000..f4e58f0 --- /dev/null +++ b/lib/cpcrslib/cpc_PutSpXOR.s @@ -0,0 +1,79 @@ +.globl _cpc_PutSpXOR + +_cpc_PutSpXOR:: ; dibujar en pantalla el sprite + ; Entradas bc-> Alto Ancho + ; de-> origen + ; hl-> destino + ; Se alteran hl, bc, de, af + + LD IX,#2 + ADD IX,SP + LD E,0 (IX) + LD D,1 (IX) + LD A,3 (IX) + LD L,4 (IX) + LD H,5 (IX) + + LD (#anchox0+#1),A ;actualizo rutina de captura + SUB #1 + CPL + LD (#suma_siguiente_lineax0+#1),A ;comparten los 2 los mismos valores. + + LD A,2 (IX) + JP cpc_PutSpXOR0 + + +.globl _cpc_PutSpriteXOR + +_cpc_PutSpriteXOR:: ; dibujar en pantalla el sprite + ; Entradas bc-> Alto Ancho + ; de-> origen + ; hl-> destino + ; Se alteran hl, bc, de, af + POP AF + POP HL + POP DE + PUSH AF + LD A,(HL) ;ANCHO + INC HL + LD (#anchox0+#1),A ;ACTUALIZO RUTINA DE CAPTURA + ;LD (ANCHOT+1),A ;ACTUALIZO RUTINA DE DIBUJO + SUB #1 + CPL + LD (#suma_siguiente_lineax0+1),A ;COMPARTEN LOS 2 LOS MISMOS VALORES. + LD A,(HL) ;ALTO + INC HL + EX DE,HL + ;LD A,(IX+4) + JP cpc_PutSpXOR0 + + +cpc_PutSpXOR0: + .DB #0XFD + LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + LD B,#7 +anchox0: +loop_alto_2x: + LD C,#4 +loop_ancho_2x: + LD A,(DE) + XOR (HL) + LD (HL),A + INC DE + INC HL + DEC C + JP NZ,loop_ancho_2x + .DB #0XFD + DEC H + RET Z + +suma_siguiente_lineax0: +salto_lineax: + LD C,#0XFF ;&07F6 ;SALTO LINEA MENOS ANCHO + ADD HL,BC + JP NC,loop_alto_2x ;SIG_LINEA_2ZZ ;SI NO DESBORDA VA A LA SIGUIENTE LINEA + LD BC,#0XC050 + ADD HL,BC + LD B,#7 ;SÓLO SE DARÍA UNA DE CADA 8 VECES EN UN SPRITE + JP loop_alto_2x + diff --git a/lib/cpcrslib/cpc_PutSprite.s b/lib/cpcrslib/cpc_PutSprite.s new file mode 100644 index 0000000..a6d6dec --- /dev/null +++ b/lib/cpcrslib/cpc_PutSprite.s @@ -0,0 +1,108 @@ +.globl _cpc_PutSprite + +_cpc_PutSprite:: +;************************************* +; SPRITE ROUTINE WITHOUT TRANSPARENCY +; Supplied by Tim Riemann +; from a German forum +; DE = source address of the sprite +; (includes header with 1B width [64byte maximum!], 1B height) +; HL = destination address +;************************************* + + POP AF + POP HL ;DESTINATION ADDRESS + POP DE ;SPRITE DATA + PUSH AF + ;EX DE,HL + LD A,#64 + SUB (HL) + ADD A + LD (width1+1),A + XOR A + SUB (HL) + LD (width2+1),A + INC HL + LD A,(HL) + INC HL +width0: + ;ex de,hl +width1: + JR width1 ;cada LDI es un byte + LDI ;se hace el salto al byte correspondiente (64-ancho) + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI + LDI +width2: + LD BC,#0X700 + EX DE,HL + ADD HL,BC + JP NC,width3 + LD BC,#0XC050 + ADD HL,BC +width3: + EX DE,HL + DEC A + JP NZ, width1 + RET + diff --git a/lib/cpcrslib/cpc_RLI.s b/lib/cpcrslib/cpc_RLI.s new file mode 100644 index 0000000..92a9385 --- /dev/null +++ b/lib/cpcrslib/cpc_RLI.s @@ -0,0 +1,39 @@ +.globl _cpc_RLI ;rota las líneas que se le digan hacia la izq y mete lo rotado por la derecha. + +_cpc_RLI:: + LD IX,#2 + ADD IX,SP + LD L,0 (IX) + LD H,1 (IX) ;posición inicial + LD A,2 (IX) ;lineas + LD (alto_cpc_RLI+1),A + LD A,3 (IX) ;ancho + LD (ancho_cpc_RLI+1),A + DEC HL +alto_cpc_RLI: + LD A,#8 ;; parametro +ciclo0_cpc_RLI: + PUSH AF + PUSH HL + INC HL + LD A,(HL) + LD D,H + LD E,L + DEC HL + LD B, #0 +ancho_cpc_RLI: + LD C,#50 ; parametro + LDDR + INC HL + LD (HL),A + POP HL + POP AF + DEC A + RET Z + LD BC,#0X800 ;salto de línea, ojo salto caracter. + ADD HL,BC + JP NC,ciclo0_cpc_RLI ;sig_linea_2zz ;si no desborda va a la siguiente linea + LD BC,#0XC050 + ADD HL,BC + JP ciclo0_cpc_RLI + diff --git a/lib/cpcrslib/cpc_RRI.s b/lib/cpcrslib/cpc_RRI.s new file mode 100644 index 0000000..d2f5b5d --- /dev/null +++ b/lib/cpcrslib/cpc_RRI.s @@ -0,0 +1,39 @@ +.globl _cpc_RRI +;cpc_RRI(unsigned int pos, unsigned char w, unsigned char h); +_cpc_RRI:: + LD IX,#2 + ADD IX,SP + LD L,0 (IX) + LD H,1 (IX) ;posición inicial + LD A,2 (IX) ;lineas + LD (alto_cpc_RRI+1),A + LD A,3 (IX) ;ancho + LD (ancho_cpc_RRI+1),A + INC HL +alto_cpc_RRI: + LD A,#8 ;; parametro +ciclo0_cpc_RRI: + PUSH AF + PUSH HL + DEC HL + LD A,(HL) + LD D,H + LD E,L + INC HL ; SOLO MUEVE 1 BYTE + LD B, #0 +ancho_cpc_RRI: + LD C,#50 ; PARAMETRO + LDIR + DEC HL + LD (HL),A + POP HL + POP AF + DEC A + RET Z + LD BC,#0X800 ;salto de línea, ojo salto caracter + ADD HL,BC + JP NC,ciclo0_cpc_RRI ;sig_linea_2zz ;si no desborda va a la siguiente linea + LD BC,#0XC050 + ADD HL,BC + JP ciclo0_cpc_RRI + diff --git a/lib/cpcrslib/cpc_Random.s b/lib/cpcrslib/cpc_Random.s new file mode 100644 index 0000000..2f2916e --- /dev/null +++ b/lib/cpcrslib/cpc_Random.s @@ -0,0 +1,34 @@ +.globl _cpc_Random + +_cpc_Random:: + + + ; LD A,(#valor_previo) + ; LD C,A +; LD L,A +; LD A,R; +; ADD L +; AND #0xB8 +; SCF +; JP PO,NO_CLR +; CCF +;NO_CLR: LD A,C + ; RLA + ; LD C,A + ; LD A,R + ; ADD C + ; LD (#valor_previo),A + ; LD L,A +; RET + + LD A,(#valor_previo) + LD L,A + LD A,R + ADD L ;LOS 2 ÚLTIMOS BITS DE A DIRÁN SI ES 0,1,2,3 + LD (#valor_previo),A + LD L,A ;SE DEVUELVE L (CHAR) + LD H,#0 + RET +valor_previo: + .db #0xFF + diff --git a/lib/cpcrslib/cpc_SetBorder.s b/lib/cpcrslib/cpc_SetBorder.s new file mode 100644 index 0000000..b1939df --- /dev/null +++ b/lib/cpcrslib/cpc_SetBorder.s @@ -0,0 +1,10 @@ +.globl _cpc_SetBorder + +_cpc_SetBorder:: + LD HL,#2 + ADD HL,SP + LD B,(HL) + ;LD B,A + LD C,B + JP 0XBC38 + diff --git a/lib/cpcrslib/cpc_SetColour.s b/lib/cpcrslib/cpc_SetColour.s new file mode 100644 index 0000000..7fd6dc3 --- /dev/null +++ b/lib/cpcrslib/cpc_SetColour.s @@ -0,0 +1,16 @@ +.globl _cpc_SetColour + +_cpc_SetColour:: ;El número de tinta 17 es el borde + LD HL,#2 + ADD HL,SP + LD A,(HL) + INC HL + ;INC HL + LD E,(HL) + LD BC,#0x7F00 ;Gate Array + OUT (C),A ;Número de tinta + LD A,#64 ;@01000000 ;Color (y Gate Array) + ADD E + OUT (C),A + RET + diff --git a/lib/cpcrslib/cpc_SetInk.s b/lib/cpcrslib/cpc_SetInk.s new file mode 100644 index 0000000..2c29464 --- /dev/null +++ b/lib/cpcrslib/cpc_SetInk.s @@ -0,0 +1,12 @@ +.globl _cpc_SetInk + +_cpc_SetInk:: + LD HL,#2 + ADD HL,SP + LD A,(HL) + INC HL + + LD B,(HL) + LD C,B + JP 0XBC32 + diff --git a/lib/cpcrslib/cpc_SetMode.s b/lib/cpcrslib/cpc_SetMode.s new file mode 100644 index 0000000..f6877b4 --- /dev/null +++ b/lib/cpcrslib/cpc_SetMode.s @@ -0,0 +1,13 @@ +.globl _cpc_SetMode + +_cpc_SetMode:: + ;ld a,l + LD HL,#2 + ADD HL,SP + LD L,(HL) ; Comprobar que el valor vaya a L!! + LD BC,#0x7F00 ;Gate array port + LD D,#140 ;@10001100 ;Mode and rom selection (and Gate Array function) + ADD D + OUT (C),A + RET + diff --git a/lib/cpcrslib/cpc_SetModo.s b/lib/cpcrslib/cpc_SetModo.s new file mode 100644 index 0000000..8e96c3b --- /dev/null +++ b/lib/cpcrslib/cpc_SetModo.s @@ -0,0 +1,9 @@ +.globl _cpc_SetModo + +_cpc_SetModo:: + ;LD A,L + LD HL,#2 + ADD HL,SP + LD a,(HL) ; COMPROBAR QUE EL VALOR VAYA A L!! + JP 0XBC0E + diff --git a/lib/cpcrslib/cpc_TileMap.s b/lib/cpcrslib/cpc_TileMap.s new file mode 100644 index 0000000..501115b --- /dev/null +++ b/lib/cpcrslib/cpc_TileMap.s @@ -0,0 +1,1332 @@ +PEEPHOLE = 0 + +.include "TileMap.h" + + + +.globl _cpc_ResetTouchedTiles + +_cpc_ResetTouchedTiles:: + LD HL,#_tiles_tocados + LD (HL),#0xFF + RET + + +.globl _cpc_InitTileMap + +_cpc_InitTileMap:: + LD HL,#0 + LD (_tiles),HL + RET + + +.globl _cpc_SetTile + +_cpc_SetTile:: + +; ld ix,#2 +; add ix,sp + +; ld e,1 (ix) +; ld a,0 (ix) + + ld hl,#2 + add hl,sp + ld a,(hl) + inc hl + ld e,(hl) + inc hl + ld c,(hl) + + ;.include "multiplication2.asm" + ;LD H, #ancho_pantalla_bytes/2 + ;LD L, #0 + LD HL,#ancho_pantalla_bytes * 256 / 2 + LD D, L + LD B, #8 + +MULT: ADD HL, HL + JR NC, NOADD + ADD HL, DE +NOADD: DJNZ MULT + + ld e,a + ;ld d,#0 ; D ya es 0 + add hl,de + + ld de,#_pantalla_juego + add hl,de + ld (hl),c + + ret + + + + +; ****************************************************** +; ** Librera de rutinas para Amstrad CPC ** +; ** Ral Simarro, Artaburu 2007 ** +; ****************************************************** + +.globl _cpc_ShowTileMap ; para una pantalla de 64x160 bytes. Superbuffer 8192bytes + + + +_cpc_ShowTileMap:: + +cont_normal: + xor a + ld (#contador_tiles),a +;Se busca el nmero de tiles en pantalla + ld hl,(#ntiles) + ld (#contador_tiles2),hl + ld hl,#_pantalla_juego + call transferir_pantalla_a_superbuffer + +;parte donde se transfiere el superbuffer completo a la pantalla + + ld de,#posicion_inicial_superbuffer + ld hl,#tiles_ocultos_ancho0*2 + add hl,de ;primero posiciona en ancho + + ; Posicin inicial lectura datos superbuffer + ld de,#ancho_pantalla_bytes + ld b,#tiles_ocultos_alto0*8 + XOR A + CP B + JR Z, NO_SUMA +bucle_alto_visible: + add hl,de + djnz bucle_alto_visible +NO_SUMA: + push hl + ld (#posicion_inicio_pantalla_visible_sb+1),HL + + +;;.otro_ancho + ld b,#ancho_pantalla_bytes-4*(tiles_ocultos_ancho0) ;;nuevo ancho + ld c,#alto_pantalla_bytes-16*(tiles_ocultos_alto0) ;;nuevo alto + + +;; a HL tb se le suma una cantidad + ld de, #tiles_ocultos_alto0*2 + ld hl,#_posiciones_pantalla + add hl,de + ld e,(hl) + inc hl + ld d,(hl) + ld hl, #2*tiles_ocultos_ancho0 + add hl,de + ld (#posicion_inicio_pantalla_visible+1),HL + ld (#posicion_inicio_pantalla_visible2+1),HL + pop de ;origen + ;HL destino + ;DE origen + ;call cpc_PutSpTM ;cambiar la rutina por una que dibuje desde superbuffer + ;ret + jp creascanes +; A partir de la direccin del vector de bloques se dibuja el mapeado en pantalla + + +transferir_pantalla_a_superbuffer: + + + PUSH HL + POP IX ;IX lleva los datos de la pantalla + LD DE,(#_posiciones_super_buffer) +bucle_dibujado_fondo: + ;Leo en HL el tile a meter en el superbuffer + LD L,0 (IX) + LD H,#0 + ADD HL,HL ;x2 + ADD HL,HL ;x4 + ADD HL,HL ;x8 + ADD HL,HL ;x16 + LD BC,#_tiles + ADD HL,BC ;hl apunta al tile a transferir + ;me falta conocer el destino. IY apunta al destino + EX DE,HL + PUSH HL + call transferir_map_sbuffer ;DE origen HL destino + + ; Inicio Mod. 29.06.2009 +; Se cambia la forma de controlar el final de datos de tiles. El #0xFF ahora s que se podr utilizar. + ld HL,(#contador_tiles2) + dec HL + LD (#contador_tiles2),HL + LD A,H + OR L + ;ret z + jp z, ret2 +; Fin Mod. 29.06.2009 + POP HL + INC IX ;Siguiente byte + + + +; LD A,(IX+0) +; CP #0xFF ;El fin de los datos se marca con #0xFF, no hay un tile que sea #0xFF + ;RET Z + EX DE,HL + LD A,(#contador_tiles) + CP #ancho_pantalla_bytes/2-1 ;31 ;son 32 tiles de ancho + JP Z,incremento2 + INC A + LD (#contador_tiles),A + INC DE + INC DE ;para pasar a la siguiente posicin + ;si ya se va por el 18 el salto es mayor, es + JP bucle_dibujado_fondo + +incremento2: + XOR A + LD (#contador_tiles),A + LD BC, #7*ancho_pantalla_bytes+2 ;450 ; 64x7+2 48x7+2 1084 ;72x15+4 + EX DE,HL + ADD HL,BC + EX DE,HL + JP bucle_dibujado_fondo + +contador_tiles: .DB 0 +contador_tiles2: .DW 0 +; Ahora se puede usar el tile 255 +ntiles: .DW ( alto_pantalla_bytes / 8 ) * ( ancho_pantalla_bytes / 2 ) + +ret2: +;Se busca el nmero de tiles en pantalla + ;ld hl,(ntiles) + ;ld (contador_tiles2),hl + pop hl +ret + + +transferir_map_sbuffer: + + ld bc,#ancho_pantalla_bytes-1 + + .DB #0xfD + LD H,#8 ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + +loop_alto_map_sbuffer: +loop_ancho_map_sbuffer: + ld A,(DE) + ld (HL),A + inc de + inc hl + ld A,(DE) + ld (HL),A + inc de + + .DB #0xfD + dec h + ret z +;hay que sumar el ancho de la pantalla en bytes para pasar a la siguiente lnea + + add HL,BC + jp loop_alto_map_sbuffer + + +.globl _cpc_PutSpTM + +_cpc_PutSpTM:: ; dibujar en pantalla el sprite + +;di +ld a,b +ld b,c +ld c,a +loop_alto_2_cpc_PutSpTM: + push bc + ld b,c + push hl +loop_ancho_2_cpc_PutSpTM: + ld A,(DE) + ld (hl),a + inc de + inc hl + djnz loop_ancho_2_cpc_PutSpTM + + ;incremento DE con el ancho de la pantalla-el del sprite + ex de,hl +ancho_mostrable: + ld bc,#4*(tiles_ocultos_ancho0) + add hl,bc + ex de,hl + pop hl + ld A,H + add #0x08 + ld H,A + sub #0xC0 + jp nc,sig_linea_2_cpc_PutSpTM + ld bc,#0xc050 + add HL,BC +sig_linea_2_cpc_PutSpTM: + pop BC + djnz loop_alto_2_cpc_PutSpTM +;ei +ret + + + + + +.globl _cpc_ShowTileMap2 + +_cpc_ShowTileMap2:: + ld bc, #256*(ancho_pantalla_bytes-4*(tiles_ocultos_ancho0))+#alto_pantalla_bytes-16*(tiles_ocultos_alto0) + +posicion_inicio_pantalla_visible: + ld hl,#0000 + + +posicion_inicio_pantalla_visible_sb: + ld hl,#0000 +papa: ; cdigo de Xilen Wars + di + ld (#auxsp),sp + ld sp,#tablascan + ld a,#alto_pantalla_bytes-16*(tiles_ocultos_alto0) ;16 alto +ppv0: + pop de ; va recogiendo de la pila!! +inicio_salto_ldi: + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + + ldi + ldi + + ldi + ldi + ldi + ldi + + + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi +CONT_salto_ldi: + ld de,#4*tiles_ocultos_ancho0 + add hl,de + +CONT_salto_ldi1: + dec a + jp nz, ppv0 + ld sp,(#auxsp) + ei + ret + +auxsp: .DW 0 + + + + + +creascanes: + ld ix,#tablascan +posicion_inicio_pantalla_visible2: + ld hl,#0000 + ld b, #alto_pantalla_bytes/8-2*tiles_ocultos_alto0 ; 20 ; num de filas. +cts0: + push bc + push hl + ld b,#8 + ld de,#2048 +cts1: + ld 0 (ix),l + inc ix + ld 0 (ix),h + inc ix + add hl,de + djnz cts1 + pop hl + ld bc,#80 + add hl,bc + pop bc + djnz cts0 +; jp prepara_salto_ldi +prepara_salto_ldi: ; para el ancho visible de la pantalla: + ld hl,#ancho_pantalla_bytes-4*tiles_ocultos_ancho0 + ld de,#inicio_salto_ldi + add hl,hl + add hl,de + ld (hl),#0xc3 + inc hl + ld de,#CONT_salto_ldi + ld (hl),e + inc hl + ld (hl),d + ret + + + + + +; MIRAR SUMA DE COORDENADAS PARA HACER SOLO UNA BUSQUEDA DE TILES +.globl _cpc_PutSpTileMap + +_cpc_PutSpTileMap:: + +.if PEEPHOLE-0 + ex de,hl +.else + ld hl,#2 ;3 + add hl,sp ;3 + + ld e,(hl) ;2 + inc hl ;1 + ld d,(hl) ;2 +.endif + + + +;segn las coordenadas x,y que tenga el sprite, se dibuja en el buffer + +; ld hl,#2 ;3 +; add hl,sp ;3 +; ld e,(hl) ;2 +; inc hl ;1 +; ld d,(hl) ;2 + + .db #0xdd + ld l,e ;2 + .db #0xdd + ld h,d ;2 + ; --> 15 NOPS + + ;Obtencion de +;dimensiones, solo usadas para calcular iteraciones -> BC +ld l,0 (ix) +ld h,1 (ix) ;dimensiones del sprite +ld C,(hl) ;; ANCHO +inc hl +ld B,(hl) ;; ANCHO +Dec b +Dec c +;->BC coord -1 + + ld l,10 (ix) + ld h,11 (ix) ;recoje coordenadas anteriores + + ld e,8 (ix) + ld d,9 (ix) + ld 10 (ix),e + ld 11 (ix),d + + +;Obtencion x0y0 -> HL +PUSH HL +Srl l ; x0/2 +Srl h +Srl h +Srl h ; y0/8 +Ex de,hl ;-> Guarda de con origen de loops + +POP hl ;(recuperar coord xoyo) +Add hl,bc ;(Suma de dimensiones) +Srl l ; (x0+ancho)/2 +Srl h +Srl h +Srl h; (y0+alto)/2 + +xor a +SBC hl,de ;diferencia entre bloque inicial y bloque con dimensiones + +;Hl tiene iteraciones en i,j partiendo de origen loops +Ld a,h +Inc a +Ld (pasos_alto_xW+1),a +Ld a,l +Inc a +;Ld (pasos_ancho_x+1),a + +;Loop from d, i veces +;Loop from e, j veces +jp macario +.db 'r','a','u','l' +macario: +pasos_ancho_xW: ; *parametro + ld b,a +bucle_pasos_anchoW: + push de +pasos_alto_xW: ; *parametro + ld c,#0 +bucle_pasos_altoW: + ; Mete E y D + call _cpc_UpdTileTable + inc d + dec c + jp nz,bucle_pasos_altoW + + pop de + inc e + dec b + jp nz,bucle_pasos_anchoW + + ret + + + + +.globl _cpc_UpdTileTable + +_cpc_UpdTileTable:: +; En DE word a comprobar (fila/columna o al revs) + LD HL,#_tiles_tocados + ;incorporo el tile en su sitio, guardo x e y +bucle_recorrido_tiles_tocados: + LD A,(HL) + CP #0xFF + JP Z,incorporar_tile ;Solo se incorpora al llegar a un hueco +; INC HL +; PUSH HL +; LD H,(HL) +; LD L,A +; SBC HL,DE +; POP HL +; RET Z +; INC HL +; JP bucle_recorrido_tiles_tocados + CP E + JP Z, comprobar_segundo_byte + INC HL + INC HL + JP bucle_recorrido_tiles_tocados +comprobar_segundo_byte: + INC HL + LD A,(HL) + CP D + RET Z ;los dos bytes son iguales, es el mismo tile. No se aade + INC HL + JP bucle_recorrido_tiles_tocados + + + +incorporar_tile: + LD (HL),E + INC HL + LD (HL),D + INC HL + LD (HL),#0xFF ;End of data +contkaka: + RET + + +;_solo_tile0: +;LD HL,#_tiles +;jp _saltate + +.globl _cpc_UpdScr + +_cpc_UpdScr:: +;lee la tabla de tiles tocados y va restaurando cada uno en su sitio. + LD IX,#_tiles_tocados ;4 +bucle_cpc_UpdScr: + LD E, 0 (IX) ;5 + LD A,#0xFF ;2 + CP E ;1 + RET Z ;RETORNA SI NO HAY MS DATOS EN LA LISTA ;2/4 + LD D,1 (IX) ;5 + INC IX ;3 + INC IX ;3 + +posicionar_superbuffer: +;con la coordenada y nos situamos en la posicin vertical y con x nos movemos a su sitio definitivo + LD C,D + SLA C ;x2 + LD B,#0 + + ; puedo usar BC para el siguiente clculo + push bc + + LD HL,#_posiciones_super_buffer + ADD HL,BC + LD C,(HL) + INC HL + LD B,(HL) + + LD L,E + SLA L + LD H,#0 + + ADD HL,BC + + pop bc + ;HL apunta a la posicin correspondiente en superbuffer + push hl + +posicionar_tile: + + LD HL,#_tabla_y_ancho_pantalla + ADD HL,BC + LD C,(HL) + INC HL + LD B,(HL) + LD L,E + LD H,#0 + ADD HL,BC +; LD DE,#_pantalla_juego +; ADD HL,DE + LD L,(HL) +; xor a +; cp l +; jp z, _solo_tile0 + + LD H,#0 + + ADD HL,HL + ADD HL,HL + ADD HL,HL + ADD HL,HL ;X16 + LD DE,#_tiles + ADD HL,DE + ;HL apunta a los datos del tile +;_saltate: + ;ex de,hl + pop de ;hl + ;RET + + + +; de: Posicin buffer +; hl: datos tile + + +transferir_map_sbuffer1: ;; ENVIA EL TILE AL SUPERBUFFER + ;ld bc,ancho_pantalla_bytes-2 ;63 + ldi ;5 + ldi ;de<-hl ;5 + ex de,hl ;1 + ld bc,#ancho_pantalla_bytes-2 ;3 + ld a,c + add HL,BC ;3 + ex de,hl ;1 + ldi ;5 + ldi ;5 + ex de,hl ;1 + ld c,a ;ld c,#ancho_pantalla_bytes-2 ;2 + add HL,BC ;3 + ex de,hl ;1 + ldi + ldi + ex de,hl + ld c,a ;ld c,#ancho_pantalla_bytes-2 + add HL,BC + ex de,hl + ldi + ldi + ex de,hl + ld c,a ;ld c,#ancho_pantalla_bytes-2 + add HL,BC + ex de,hl + ldi + ldi + ex de,hl + ld c,a ;ld c,#ancho_pantalla_bytes-2 + add HL,BC + ex de,hl + ldi + ldi + ex de,hl + ld c,a ;ld c,#ancho_pantalla_bytes-2 + add HL,BC + ex de,hl + ldi + ldi + ex de,hl + ld c,a ;ld c,#ancho_pantalla_bytes-2 + add HL,BC + ex de,hl + ldi + ldi +jp bucle_cpc_UpdScr + + + +.globl _cpc_PutSpTileMap2b + +_cpc_PutSpTileMap2b:: + +;segn las coordenadas x,y que tenga el sprite, se dibuja en el buffer + + ; ld ix,#2 + ; add ix,sp + + + ; ld l,0 (ix) + ; ld h,1 (ix) ;HL apunta al sprite + + ; push hl + ; pop ix + + + ld hl,#2 ;3 + add hl,sp ;3 + ld e,(hl) ;2 + inc hl ;1 + ld d,(hl) ;2 + + .db #0xdd + ld l,e ;2 + .db #0xdd + ld h,d ;2 + ; --> 15 NOPS + + + + ;lo cambio para la rutina de multiplicar + ld a,8 (ix) + ld e,9 (ix) + + +;include "multiplication1.asm" + + + ;ld h, #ancho_pantalla_bytes + ;LD L, #0 + LD HL,#ancho_pantalla_bytes * 256 + LD D, L + LD B, #8 + +MULT2: ADD HL, HL + JR NC, NOADD2 + ADD HL, DE +NOADD2: DJNZ MULT2 + + + + + + ;ld b,#0 + ld e,a + add hl,de + ld de,#posicion_inicial_superbuffer + add hl,de + ;hl apunta a la posicin en buffer (destino) + + + ld 4 (ix),l ;update superbuffer address + ld 5 (ix),h + + + ld e,0 (ix) + ld d,1 (ix) ;HL apunta al sprite + + ;con el alto del sprite hago las actualizaciones necesarias a la rutina + ld a,(de) + ld (#loop_alto_map_sbuffer2+2),a + ld b,a + ld a,#ancho_pantalla_bytes + sub b + ;ld (#ancho_22+1),a + ld c,a + inc de + ld a,(de) + inc de + + ;ld a,16 ;necesito el alto del sprite + + + +sp_buffer_mask2: + ld b,#0 +ancho_22: + ;ld c,#ancho_pantalla_bytes-4 ;60 ;;DEPENDE DEL ANCHO + + .db #0xDD + LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + ;ld ixh,a +loop_alto_map_sbuffer2: + .db #0xDD + LD L,#4 ;ANCHO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + ;ld ixl,#4 + ex de,hl +loop_ancho_map_sbuffer2: + + + LD A,(hl) ;leo el byte del fondo + ;AND (HL) ;lo enmascaro + ;INC HL + ;OR (HL) ;lo enmascaro + LD (de),A ;actualizo el fondo + INC DE + INC HL + + + .db #0xDD + DEC L ;resta ancho + ;dec ixl + JP NZ,loop_ancho_map_sbuffer2 + + .db #0xDD + dec H + ;dec ixh + ret z + EX DE,HL +;hay que sumar 72 bytes para pasar a la siguiente lnea + add HL,BC + jp loop_alto_map_sbuffer2 + + +.globl _cpc_PutMaskSpTileMap2b + +_cpc_PutMaskSpTileMap2b:: +;segn las coordenadas x,y que tenga el sprite, se dibuja en el buffer + .if PEEPHOLE-0 + ex de,hl +.else + + ld hl,#2 ;3 + add hl,sp ;3 + ld e,(hl) ;2 + inc hl ;1 + ld d,(hl) ;2 +.endif + + +; ld hl,#2 ;3 +; add hl,sp ;3 +; ld e,(hl) ;2 +; inc hl ;1 +; ld d,(hl) ;2 + + .db #0xdd + ld l,e ;2 + .db #0xdd + ld h,d ;2 + ; --> 15 NOPS + + + ld a,8 (ix) + ld e,9 (ix) + +;include "multiplication1.asm" + ;ld h, #ancho_pantalla_bytes + ;LD L, #0 + LD HL,#ancho_pantalla_bytes * 256 + LD D, L + LD B, #8 + +MULT3: ADD HL, HL + JR NC, NOADD3 + ADD HL, DE +NOADD3: DJNZ MULT3 + + + + ;ld b,#0 + ld e,a + add hl,de + ;HL=E*H+D + + + + + + ld de,#posicion_inicial_superbuffer + add hl,de + ;hl apunta a la posicin en buffer (destino) + + ld 4 (ix),l ;update superbuffer address + ld 5 (ix),h + + ld e,0 (ix) + ld d,1 (ix) ;HL apunta al sprite + + ;con el alto del sprite hago las actualizaciones necesarias a la rutina + ld a,(de) + ld (#loop_alto_map_sbuffer3+2),a + ld b,a + ld a,#ancho_pantalla_bytes + sub b + ;ld (#ancho_23+1),a + ld c,a + inc de + ld a,(de) + inc de + + ;ld a,16 ;necesito el alto del sprite + + + +sp_buffer_mask3: + ld b,#0 +ancho_23: + ;ld c,#ancho_pantalla_bytes-4 ;60 ;;DEPENDE DEL ANCHO + + .db #0xdd + LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + ;ld ixh,a +loop_alto_map_sbuffer3: + .db #0xdd + LD L,#4 ;ANCHO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + ;ld ixl,4 + ex de,hl +loop_ancho_map_sbuffer3: + + + LD A,(DE) ;leo el byte del fondo + AND (HL) ;lo enmascaro + INC HL + OR (HL) ;lo enmascaro + LD (DE),A ;actualizo el fondo + INC DE + INC HL + + .db #0xdD + DEC L ;resta ancho + ;dec ixl + JP NZ,loop_ancho_map_sbuffer3 + + .db #0xdd + dec H + ;dec ixh + ret z + EX DE,HL +;hay que sumar 72 bytes para pasar a la siguiente lnea + add HL,BC + jp loop_alto_map_sbuffer3 + + + + + + + + +.globl _cpc_PutMaskInkSpTileMap2b + +_cpc_PutMaskInkSpTileMap2b:: +;segn las coordenadas x,y que tenga el sprite, se dibuja en el buffer + + ld hl,#2 ;3 + add hl,sp ;3 + ld e,(hl) ;2 + inc hl ;1 + ld d,(hl) ;2 + + .db #0xdd + ld l,e ;2 + .db #0xdd + ld h,d ;2 + ; --> 15 NOPS + + + ld a,8 (ix) + ld e,9 (ix) + +;include "multiplication1.asm" + ;ld h, #ancho_pantalla_bytes + ;LD L, #0 + LD HL,#ancho_pantalla_bytes * 256 + LD D, L + LD B, #8 + +MULT7: ADD HL, HL + JR NC, NOADD7 + ADD HL, DE +NOADD7: DJNZ MULT7 + + ld e,a + add hl,de + ;HL=E*H+D + + ld de,#posicion_inicial_superbuffer + add hl,de + ;hl apunta a la posicin en buffer (destino) + + ld 4 (ix),l ;update superbuffer address + ld 5 (ix),h + + ld e,0 (ix) + ld d,1 (ix) ;HL apunta al sprite + + ;con el ancho del sprite hago las actualizaciones necesarias a la rutina + ld a,(de) + ld (#loop_alto_map_sbuffer7+2),a + ld b,a + ld a,#ancho_pantalla_bytes + sub b + ;ld (#ancho_27+1),a + ld c,a + inc de + ld a,(de) + inc de + + +sp_buffer_mask7: + ld b,#0 +ancho_27: + ;ld c,#ancho_pantalla_bytes-4 ;60 ;;DEPENDE DEL ANCHO + + .db #0xdd + LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + ;ld ixh,a +loop_alto_map_sbuffer7: + .db #0xdd + LD L,#4 ;ANCHO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE + ;ld ixl,4 + ex de,hl + +loop_ancho_map_sbuffer7: + + + LD A,(hl) ;leo el byte del fondo + or a + jp z, cont7 + + LD (DE),A ;actualizo el fondo +cont7: + INC DE + INC HL + + .db #0xdD + DEC L ;resta ancho + ;dec ixl + JP NZ,loop_ancho_map_sbuffer7 + + .db #0xdd + dec H + ;dec ixh + ret z + EX DE,HL +;hay que sumar 72 bytes para pasar a la siguiente lnea + add HL,BC + jp loop_alto_map_sbuffer7 + + + +.globl _cpc_ScrollLeft00 + +_cpc_ScrollLeft00:: + + ;se decrementa cada posiciones_pantalla + LD HL,#_posiciones_pantalla + ld b,#20 + buc_suma1: + DEC (HL) + INC HL + INC HL + djnz buc_suma1 + + ld hl,(#posicion_inicio_pantalla_visible_sb+1) + inc HL + ld (#posicion_inicio_pantalla_visible_sb+1),HL + + RET + +.globl _cpc_ScrollLeft01 + +_cpc_ScrollLeft01:: + + ;se incrementa cada posiciones_pantalla + LD HL,#_posiciones_pantalla + ld b,#20 + buc_suma14: + INC (HL) + INC HL + INC HL + djnz buc_suma14 + + + ld hl,(#posicion_inicio_pantalla_visible_sb+1) + dec HL + ld (#posicion_inicio_pantalla_visible_sb+1),HL + + + ld hl,#_pantalla_juego+1 + ld de,#_pantalla_juego + ld bc,#alto_pantalla_bytes*ancho_pantalla_bytes/16 -1 + LDIR + + ld hl,#posicion_inicial_superbuffer+2 + ld de,#posicion_inicial_superbuffer + ld bc,#alto_pantalla_bytes*ancho_pantalla_bytes -1 + LDIR + + RET + + + + +.globl _cpc_ScrollRight00 + +_cpc_ScrollRight00:: ;;scrollea el area de pantalla de tiles + + ;se decrementa cada posiciones_pantalla + LD HL,#_posiciones_pantalla + ld b,#20 + buc_suma12: + INC (HL) + INC HL + INC HL + djnz buc_suma12 + + + ld hl,(#posicion_inicio_pantalla_visible_sb+1) + dec HL + ld (#posicion_inicio_pantalla_visible_sb+1),HL + + RET + + +.globl _cpc_ScrollRight01 + +_cpc_ScrollRight01:: ;;scrollea el area de pantalla de tiles + + ;se incrementa cada posiciones_pantalla + LD HL,#_posiciones_pantalla + ld b,#20 + buc_suma15: + DEC (HL) + INC HL + INC HL + djnz buc_suma15 + + + ld hl,(#posicion_inicio_pantalla_visible_sb+1) + inc HL + ld (#posicion_inicio_pantalla_visible_sb+1),HL + + ld hl,#_pantalla_juego+alto_pantalla_bytes*ancho_pantalla_bytes/16-1 + ld de,#_pantalla_juego+alto_pantalla_bytes*ancho_pantalla_bytes/16 + ld bc,#alto_pantalla_bytes*ancho_pantalla_bytes/16 -1 ;-1 + LDDR + + ;;scrollea el superbuffer + ld hl,#posicion_inicial_superbuffer+alto_pantalla_bytes*ancho_pantalla_bytes-2 ; pantalla_juego+alto_pantalla_bytes*ancho_pantalla_bytes/16-1 + ld de,#posicion_inicial_superbuffer+alto_pantalla_bytes*ancho_pantalla_bytes ;pantalla_juego+alto_pantalla_bytes*ancho_pantalla_bytes/16 + ld bc,#alto_pantalla_bytes*ancho_pantalla_bytes-1 ;-1 + LDDR + RET + +.globl _cpc_SetTouchTileXY + +_cpc_SetTouchTileXY:: + + ;ld ix,#2 + ;add ix,sp + + ;ld d,1 (ix) + ;ld e,0 (ix) + + + ld hl,#2 + add hl,sp + ld e,(hl) + inc hl + ld d,(hl) + inc hl + ld c,(hl) + + + ;ld d,e + ;ld e,c + call _cpc_UpdTileTable + + ;ld e,1 (ix) + ;ld a,0 (ix) + ld a,e + ld e,d +;include "multiplication2.asm" + ;ld h, #ancho_pantalla_bytes/2 + ;LD L, #0 + LD HL,#ancho_pantalla_bytes * 256 / 2 + LD D, L + LD B, #8 + +MULT4: ADD HL, HL + JR NC, NOADD4 + ADD HL, DE +NOADD4: DJNZ MULT4 + + + ld e,a + ;ld d,#0 + add hl,de + ld de,#_pantalla_juego + add hl,de + ;ld a,2 (ix) + ld (hl),c + ret + + +.globl _cpc_ReadTile + +_cpc_ReadTile:: + + +; ld ix,#2 +; add ix,sp +; ld e,1 (ix) +; ld a,0 (ix) + + ld hl,#2 + add hl,sp + ld a,(hl) + inc hl + ld e,(hl) + + + +; ld hl,2 +; add hl,sp ; Es la forma de pasar parmetros? Se pasan en SP+2? en la pila? +; ld E,(hl) ;Y +; inc hl +; inc hl +; ld a,(hl) ;X + +; include "multiplication2.asm" + ;ld h, #ancho_pantalla_bytes/2 + ;LD L, #0 + LD HL,#ancho_pantalla_bytes * 256 / 2 + LD D, L + LD B, #8 + +MULT5: ADD HL, HL + JR NC, NOADD5 + ADD HL, DE +NOADD5: DJNZ MULT5 + + + + ld e,a + ;ld d,#0 + add hl,de ;SUMA X A LA DISTANCIA Y*ANCHO + ld de,#_pantalla_juego + add hl,de + ld l,(hl) + ld h,#0 + ret + + +.globl _cpc_SuperbufferAddress + +_cpc_SuperbufferAddress:: +; ld ix,#2 +; add ix,sp + +; ld l,0 (ix) +; ld h,1 (ix) ;HL apunta al sprite + +; push hl +; pop ix + + ld hl,#2 ;3 + add hl,sp ;3 + ld e,(hl) ;2 + inc hl ;1 + ld d,(hl) ;2 + + .db #0xdd + ld l,e ;2 + .db #0xdd + ld h,d ;2 + ; --> 15 NOPS + + + ;lo cambio para la rutina de multiplicar + ld a,8 (ix) + ld e,9 (ix) +; include "multiplication1.asm" + ;ld h, #ancho_pantalla_bytes + ;LD L, #0 + LD HL,#ancho_pantalla_bytes * 256 + LD D, L + LD B, #8 + +MULT6: ADD HL, HL + JR NC, NOADD6 + ADD HL, DE +NOADD6: DJNZ MULT6 + + + ;ld b,#0 + ld e,a + add hl,de + ld de,#posicion_inicial_superbuffer + add hl,de + ;hl apunta a la posicin en buffer (destino) + ld 4 (ix),l + ld 5 (ix),h + ret + + + +tablascan: ;defs 20*16 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 +.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + diff --git a/lib/cpcrslib/cpc_UnExoOpt.s b/lib/cpcrslib/cpc_UnExoOpt.s new file mode 100644 index 0000000..14197cc --- /dev/null +++ b/lib/cpcrslib/cpc_UnExoOpt.s @@ -0,0 +1,183 @@ +; ****************************************************** +; ** Librera de rutinas SDCC para Amstrad CPC ** +; ** Ral Simarro (Artaburu) - 2009, 2012 ** +; ****************************************************** + + +;************************************* +; UNEXO +;************************************* + + +; Exomizer 2 Z80 decoder +; by Metalbrain +; +; optimized by Antonio Villena +; +; compression algorithm by Magnus Lind + +;input: hl=compressed data start +; de=uncompressed destination start +; +; you may change exo_mapbasebits to point to any free buffer + + +.globl _cpc_UnExo + +_cpc_UnExo:: + +; POP AF +; POP HL ;DESTINATION ADDRESS +; POP DE ;SPRITE DATA +; PUSH AF + + LD IX,#2 + ADD IX,SP + LD e,2 (IX) + LD d,3 (IX) ;DESTINO + LD l,0 (IX) + LD h,1 (IX) ;TEXTO ORIGEN + + di + call deexo + ei + ret + +deexo: + ld iy, #exo_mapbasebits + ld a,#128 + ld b,#52 + push de +exo_initbits: + ex af,af' + ld a,b + sub #4 + and #15 + jr nz,exo_node1 + ld de,#1 ;DE=b2 +exo_node1: + ld c,#16 + ex af, af' +exo_get4bits: + call exo_getbit + rl c + jr nc,exo_get4bits + ld (iy),c ;bits[i]=b1 + push hl + ld hl,#1 + .db #210 ;3 bytes nop (JP NC) +exo_setbit: + add hl,hl + dec c + jr nz,exo_setbit + ld 52 (iy),e + ld 104 (iy),d ;base[i]=b2 + add hl,de + ex de,hl + inc iy + pop hl + djnz exo_initbits + inc c +exo_literalseq: + pop de +exo_literalcopy: + ldir ;copy literal(s) +exo_mainloop: + ld c,#1 + call exo_getbit ;literal? + jr c,exo_literalcopy + ld c,#255 +exo_getindex: + inc c + call exo_getbit + jr nc,exo_getindex + bit 4,c + jr z,exo_continue + bit 0, c + ret z + push de + ld d,#16 + call exo_getbits + jr exo_literalseq +exo_continue: + push de + call exo_getpair + push bc + pop ix + ld de,#560 ;512+48 ;1? + inc b + djnz exo_dontgo + dec c + jr z, exo_goforit + dec c ;2? +exo_dontgo: + ld de,#1056 ;1024+32 + jr z,exo_goforit + ld e,#16 +exo_goforit: + call exo_getbits + ex af, af' + ld a,e + add a,c + ld c,a + ex af, af' + call exo_getpair ;bc=offset + pop de ;de=destination + push hl + ld h,d + ld l,e + sbc hl,bc ;hl=origin + push ix + pop bc ;bc=lenght + ldir + pop hl ;Keep HL, DE is updated + jr exo_mainloop ;Next! + +exo_getpair: + ld iy,#exo_mapbasebits + ld b,#0 + add iy,bc + ld d,(iy) + call exo_getbits + push hl + ld l, 52 (iy) + ld h, 104 (iy) + add hl, bc ;Always clear C flag + ld b, h + ld c, l + pop hl + ret + +exo_getbits: + ld bc,#0 ;get D bits in BC +exo_gettingbits: + dec d + ret m + call exo_getbit + rl c + rl b + jr exo_gettingbits + +exo_getbit: + add a, a ;get one bit + ret nz + ld a, (hl) + inc hl + adc a, a + ret + +exo_mapbasebits: + ;defs 156 ;tables for bits, baseL, baseH + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 + .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 \ No newline at end of file diff --git a/lib/cpcrslib/cpc_Uncrunch.s b/lib/cpcrslib/cpc_Uncrunch.s new file mode 100644 index 0000000..7eba8c3 --- /dev/null +++ b/lib/cpcrslib/cpc_Uncrunch.s @@ -0,0 +1,308 @@ +; ****************************************************** +; ** Librera de rutinas SDCC para Amstrad CPC ** +; ** Ral Simarro (Artaburu) - 2009, 2012 ** +; ****************************************************** + + +;************************************* +; UNCRUNCH +;************************************* + + +.globl _cpc_Uncrunch + +_cpc_Uncrunch:: +; datos necesarios que vienen en la pila: +; ORIGEN HL +; DESTINO DE + + ;Ojo, para que el pucrunch funcione hay que coger y quitar el salto de las interrupciones. + DI + LD HL,(#0X0038) + LD (#datos_int),HL + + LD HL,#0X00C9 + LD (#0x0038),HL + EI + +;POP AF +;POP HL +;POP DE +;PUSH AF + LD IX,#2 + ADD IX,SP + LD e,2 (IX) + LD d,3 (IX) ;DESTINO + LD l,0 (IX) + LD h,1 (IX) ;TEXTO ORIGEN + + +pucrunch: + PUSH DE ; destination pointer to 2nd register + EXX ; set + POP DE + + + PUSH HL + PUSH DE + PUSH BC + PUSH AF + + EXX + + ; read the header self-modifying the + ; parameters straight into the code + ; skip useless data + + + LD BC,#6 + ADD HL,BC + + LD A, (HL) ; starting escape + INC HL + LD (#esc+1), A + + INC HL ; skip useless data + INC HL + + LD A, (HL) ; number of escape bits + INC HL + LD (#escb0+1), A + LD (#escb1+1), A + + LD B, A ; 8 - escape bits + LD A, #8 + SUB B + LD (#noesc+1), A + + LD A, (HL) ; maxGamma + 1 + INC HL + LD (#mg+1), A + + LD B, A ; 8 - maxGamma + LD A, #9 + SUB B + LD (#longrle+1), A + + LD A, (HL) ; (1 << maxGamma) + INC HL + LD (#mg1+1), A + + ADD A, A ; (2 << maxGamma) - 1 + DEC A + LD (#mg21+1), A + + LD A, (HL) ; extra lz77_0 position bits + INC HL + LD (#elzpb+1), A + + INC HL ; skip useless data + INC HL + + LD E, (HL) ; RLE table length + LD (#rlet+1), HL ; RLE table pointer + INC HL + LD D, #0 + ADD HL, DE + + LD C, #0X80 ; start decompression + JP loop_u + +newesc: + ld a, (#esc+1) ; save old escape code + ld d, a + +escb0: + LD B, #2 ; ** parameter + XOR A ; get new escape code + CALL get_bits + LD (#esc+1), A + + LD A, D + +noesc: + LD B, #6 ; ** parameter + CALL get_bits ; get more bits to complete a byte + + EXX ; output the byte + LD (DE), A + INC DE + EXX + +loop_u: + XOR A +escb1: + LD B, #2 ; ** parameter + CALL get_bits ; get escape code +esc: + CP #0 ; ** PARAMETER + JP NZ, noesc + + CALL get_gamma ; get length + EXX + LD B, #0 + LD C, A + EXX + + CP #1 + JP NZ, lz77_0 ; lz77_0 + + XOR A + CALL get_bit + JP NC, lz77_0_2 ; 2-byte lz77_0 + + CALL get_bit + JP NC, newesc ; escaped literal byte + + CALL get_gamma ; get length + EXX + LD B, #1 + LD C, A + EXX + +mg1: + CP #64 ; ** parameter + JP C, chrcode ; short RLE, get bytecode + +longrle: + LD B, #2 ; ** parameter + CALL get_bits ; complete length LSB + EX AF, AF' + + CALL get_gamma ; length MSB + EXX + LD B, A + EX AF, AF' + LD C, A + EXX + +chrcode: + CALL get_gamma ; get byte to repeat + + PUSH HL +rlet: + LD HL, #0X0000 ; ** parameter + LD D, #0 + LD E, A + ADD HL, DE + + CP #32 + LD A, (HL) + POP HL + JP C, dorle + + LD A, E ; get 3 more bits to complete the + LD B, #3 ; byte + CALL get_bits + +dorle: + EXX ; output the byte n times + INC C +dorlei: + LD (DE), A + INC DE + DEC C + JP NZ, dorlei + DEC B + JP NZ, dorlei + EXX + JP loop_u + +lz77_0: + CALL get_gamma ; offset MSB +mg21: + CP #127 ; ** parameter + + ; ret z + + JP Z, fin ; EOF, return + + DEC A ; (1...126 -> 0...125) +elzpb: + LD B, #0 ; ** parameter + CALL get_bits ; complete offset MSB + +lz77_0_2: + EX AF, AF' + LD B, #8 ; offset LSB + CALL get_bits + CPL ; xor'ed by the compressor + + EXX ; combine them into offset + LD L, A + EX AF, AF' + LD H, A + INC HL + + XOR A ; CF = 0 + + PUSH DE ; (current output position) - (offset) + EX DE, HL + SBC HL, DE + POP DE + + INC BC + + LDIR ; copy + EXX + JP loop_u + +;## Get a bit from the source stream. +;## Return CF = result +get_bit: + SLA C ; shift next bit into CF + RET NZ + LD C, (HL) ; get next byte + INC HL ; increase source stream pointer + RL C ; shift next bit into CF, bit0 = 1 + RET + +;## Get multiple bits from the source stream. +;## In B = number of bits to get +;## Return A = result +get_bits: + DEC B + RET M + SLA C ; shift next bit into CF + JP NZ, gb1 + LD C, (HL) ; get next byte + INC HL ; increase source stream pointer + RL C ; shift next bit into CF, bit0 = 1 +gb1: + RLA ; rotate next bit into A + JP get_bits + +;## Get an Elias Gamma coded value from the source stream. +;## Return A = result +get_gamma: + LD B, #1 +mg: + LD A, #7 ; ** parameter +gg1: + CALL get_bit ; get bits until 0-bit or max + JR NC, gg2 + INC B + CP B + JP NZ, gg1 +gg2: + LD A, #1 ; GET THE ACTUAL VALUE + DEC B + JP get_bits + +fin: + ; Restauramos los registros dobles y vuelta limpia + EXX + POP AF + POP BC + POP DE + POP HL + EXX + + ;RET + DI + LD HL,(#datos_int) + LD (#0X0038),HL ;RESTAURO LA INTERRUPCIN ORIGINAL + EI + RET +datos_int: + .DW #0 \ No newline at end of file diff --git a/lib/cpcrslib/cpcrslib.h b/lib/cpcrslib/cpcrslib.h new file mode 100644 index 0000000..91bee0d --- /dev/null +++ b/lib/cpcrslib/cpcrslib.h @@ -0,0 +1,116 @@ + +#ifndef __cpcrslib_h__ +#define __cpcrslib_h__ + + + + + + + +void cpc_UnExo(char *origen, int destino); +void cpc_Uncrunch(char *origen, int destino); + + +void cpc_SetMode( char color); +void cpc_SetModo( char x); +void cpc_SetColour(unsigned char num, char color); +void cpc_SetInk(unsigned char num, unsigned char color); +void cpc_SetBorder( char color); +unsigned char cpc_Random(void); + +void cpc_ClrScr(void); + +void cpc_PutSprite(char *sprite, int posicion); +void cpc_PutSp(char *sprite, char height, char width, int address); +void cpc_PutSp4x14(char *sprite, int address); +void cpc_PutSpriteXOR(char *sprite, int posicion); +void cpc_PutSpXOR(char *sprite, char height, char width, int address); +void cpc_PutSpriteTr(char *sprite, int *posicion); +void cpc_PutSpTr(char *sprite, char height, char width, int address); +void cpc_GetSp(char *sprite, char alto, char ancho, int posicion); +void cpc_PutMaskSprite(char *sprite,unsigned int addr); +//void cpc_PutMaskSprite(struct sprite *spr,unsigned int *addr); +void cpc_PutMaskSp(char *sprite, char alto, char ancho, int posicion); +void cpc_PutMaskSp4x16(char *sprite,unsigned int addr); +void cpc_PutMaskSp2x8(char *sprite,unsigned int addr); + + +unsigned char cpc_CollSp(char *sprite, char *sprite2); + + +// TILE MAP: +void cpc_InitTileMap(void); +void cpc_SetTile(unsigned char x, unsigned char y, unsigned char b); +void cpc_ShowTileMap(); +void cpc_ShowTileMap2(void); +void cpc_ResetTouchedTiles(void); + +void cpc_PutSpTileMap(char *sprite); +void cpc_PutSpTileMapF(char *sprite); +void cpc_UpdScr(void); +void cpc_PutSpTileMap2b(char *sprite); +void cpc_PutMaskSpTileMap2b(char *sprite); +void cpc_PutMaskInkSpTileMap2b(char *sprite); +void cpc_PutTrSpTileMap2b(char *sprite); +void cpc_PutTrSpriteTileMap2b(char *sprite); + + +void cpc_SpUpdY(char *sprite, char valor); +void cpc_SpUpdX(char *sprite, char valor); + +void cpc_ScrollRight00(void); +void cpc_ScrollRight01(void); +void cpc_ScrollLeft00(void); +void cpc_ScrollLeft01(void); +void cpc_ScrollRight(void); +void cpc_ScrollLeft(void); + +void cpc_SetTouchTileXY(unsigned char x, unsigned char y, unsigned char t); +unsigned char cpc_ReadTile(unsigned char x, unsigned char y); +void cpc_SuperbufferAddress(char *sprite); + +// **************** + + + + + + +void cpc_RRI(unsigned int pos, unsigned char w, unsigned char h); +void cpc_RLI(unsigned int pos, unsigned char w, unsigned char h); + + +int cpc_AnyKeyPressed(void); +void cpc_ScanKeyboard(void); +char cpc_TestKeyF(char number); +void cpc_DeleteKeys(void); +void cpc_AssignKey(unsigned char tecla, int valor); +unsigned char cpc_TestKey(unsigned char tecla); +void cpc_RedefineKey(unsigned char tecla); + +int cpc_GetScrAddress(char x, char y); + +void cpc_PrintStr(char *text); + +void cpc_EnableFirmware(void); +void cpc_DisableFirmware(void); + +void cpc_SetFont(unsigned char first_char, unsigned char *font_def); + +void cpc_PrintGphStr(char *text, int destino); +void cpc_PrintGphStrM1(char *text, int destino); +void cpc_PrintGphStr2X(char *text, int destino); +void cpc_PrintGphStrM12X(char *text, int destino); + +void cpc_PrintGphStrXY(char *text, unsigned char a, unsigned char b); +void cpc_PrintGphStrXYM1(char *text, unsigned char a, unsigned char b); +void cpc_PrintGphStrXY2X(char *text, unsigned char a, unsigned char b); +void cpc_PrintGphStrXYM12X(char *text, unsigned char a, unsigned char b); +void cpc_SetInkGphStr(unsigned char a, unsigned char b); +void cpc_SetInkGphStrM1(unsigned char a, unsigned char b); + +void cpc_PrintGphStrStd(char color, char *cadena, int destino); +void cpc_PrintGphStrStdXY(char color, char *cadena, char x, char y); + +#endif /* __cpcrslib_h__ */ diff --git a/lib/cpcrslib/cpcwyzlib.h b/lib/cpcrslib/cpcwyzlib.h new file mode 100644 index 0000000..b0c04c4 --- /dev/null +++ b/lib/cpcrslib/cpcwyzlib.h @@ -0,0 +1,18 @@ + +#ifndef __cpcwyzlib_h__ +#define __cpcwyzlib_h__ + + + +extern void cpc_WyzLoadSong(unsigned char numero); +extern void cpc_WyzStartEffect(unsigned char canal, unsigned char efecto); +//extern void cpc_WyzSetPlayerOn(void); +// use WyzPlayerOn instead! +extern void cpc_WyzSetPlayerOff(void); +// WARNING: use WyzPlayerOff instead! +extern void cpc_WyzConfigurePlayer(unsigned char valor); +extern unsigned char cpc_WyzTestPlayer(void); +extern void cpc_WyzInitPlayer(unsigned char *sonidos[], unsigned char *pautas[], unsigned char *efectos[], unsigned char *canciones[]); +extern void cpc_WyzSetTempo(unsigned char tempo); + +#endif diff --git a/lib/cpcrslib/make.bat b/lib/cpcrslib/make.bat new file mode 100644 index 0000000..77a7e8c --- /dev/null +++ b/lib/cpcrslib/make.bat @@ -0,0 +1,19 @@ +del *.rel +del *.lib +sdasz80 -o cpcrslib.s +sdasz80 -o GphStr.s +sdasz80 -o Sprites.s +sdasz80 -o Keyboard.s +sdasz80 -o UnExoOpt.s +sdasz80 -o Uncrunch.s +sdasz80 -o GphStrStd.s +sdasz80 -o TileMap.s +sdasz80 -o Wyz.s + + + +sdar rc cpcrslib.lib cpcrslib.rel GphStr.rel Sprites.rel Keyboard.rel UnExoOpt.rel Uncrunch.rel GphStrStd.rel TileMap.rel + +sdar rc cpcwyzlib.lib Wyz.rel +copy cpcrslib.lib C:\sdcc\lib\z80 +copy cpcwyzlib.lib C:\sdcc\lib\z80 diff --git a/lib/ucl.h b/lib/ucl.h new file mode 100644 index 0000000..9cd91e8 --- /dev/null +++ b/lib/ucl.h @@ -0,0 +1,5 @@ +#ifndef _UCL_H +#define _UCL_H +extern void ucl_uncompress(const unsigned char *src, unsigned char *dst); +#endif + diff --git a/lib/ucl.s b/lib/ucl.s new file mode 100644 index 0000000..68b1b48 --- /dev/null +++ b/lib/ucl.s @@ -0,0 +1,360 @@ +; UCLZ80: -*- asm -*- +; 2bunpack: unpack data compressed with M.F.X.J. Oberhumer''s +; UCL/2B algorithm. Decompressor for Z80 (c) 2000 Adam D. Moss +; - All rights reserved +; +; Version 0.99-beta2: 2000-10-25 +; ** COMMENTS, FIXES ETC ARE WELCOMED ** + If you use this, I''d love to hear. +; +; Permission is hereby granted, free of #0xcarge, 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 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. +; +; (In laymans'' terms this code is essentially public domain.) +; +; Latest versions and docs, plus pointers to associated utilities and +; M.F.X.J. Oberhumer''s *compressor* for UCL/2B streams are always +; available from the UCLZ80 home page: +; +; +; +; UPDATE: http://icculus.org/~aspirin/uclz80/ +; +; RELEASE HISTORY: +; v0.99-beta2: 2000-10-25: Rearrangement, comments, public release +; v0.99-beta1: 2000-07-30: Optimizations, comments and fixes +; v0.50 : 2000-07-22: Initial version + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Assembly syntax compatible with ZMAC and ASL cross-assemblers. +; Undocumented Z80 instructions have been inserted in byte form. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; CALL: +; L2bunpack +; INPUTS: +; bc = PACKED DATA SOURCE ADDRESS +; de = UNPACKED DATA DESTINATION ADDRESS +; STACK USAGE: +; 2 bytes excluding call overhead +; REGISTER USAGE: +; leaves IY, IXH and all alternative registers intact +; SIZE: +; 245 bytes +; +; NOTES: +; ''In-place'' unpacking of overlapping src/dest is also supported; +; use external utility to find the maximum overlap for a given +; block of data ((UNPACKED_SIZE - n) where n is usually around 7-10 +; bytes). +; +; No #0xcecking of data integrity is performed by this unpacker. +; +; The length of the unpacked data is implicit in the packed stream; +; you should know in advance the length to whi#0xc a given compressed +; stream unpacks (ie. from out-of-band metadata), to provide enough +; space in the destination memory area. + +.globl _ucl_uncompress + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; loops taken out of line +L2bloop1_0: ; DON''T CALL HERE, these functions are just here for JR-locality + ;;;; bb = *src, src++ + ld a, (bc) ; get *src + inc bc ; src++ + scf + rla ; ADM: could use undoc''d SLL + .db #0x0DD,#0x6F ; LD IXL,A + + jr C, L2bloop1_work ; we carried, do the work -ADM:GetStats + jp L2bloop1_end ; otherwise drop out + +L2bloop2a_0: + ;;;; bb = *src, src++ + ld a, (bc) ; get *src + inc bc ; src++ + scf + rla ; ADM: could use undoc''d SLL + .db #0x0DD,#0x6F ; LD IXL,A + + jr NC, L2bloop2a_skip_set + jp L2bloop2a_set + +L2bloop2b_0: + ;;;; bb = *src, src++ + ld a, (bc) ; get *src + inc bc ; src++ + scf + rla ; ADM: could use undoc''d SLL + .db #0x0DD,#0x6F ; LD IXL,A + + jr C, L2bloop2b_end ; if !bit then end loop + jp L2bloop2a ; if bit then restart big loop + + +L2bjmp3_0: + ;;;; bb = *src, src++ + ld a, (bc) ; get *src + inc bc ; src++ + scf + rla ; ADM: could use undoc''d SLL + .db #0x0DD,#0x6F ; LD IXL,A + + jp L2bjmp3_r + +L2b_term: ; springboard placed here to be within JR r#0xeac + jp L2b_end + +;;; +;;; my EP +_ucl_uncompress:: + ld ix, #2 + add ix, sp + ld c, (ix) + ld b, 1(ix) + ld e, 2(ix) + ld d, 3(ix) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CALL HERE: +L2bunpack: + ; init variables + .db #0x0DD,#0x2E,#0x00 ; LD IXL, 0; bit-bucket lives in IXL + ld hl, #0x1 + ld (prev_doffset), hl + +L2bmain: +L2bloop1: ;;;; while nextbit()==1 *dest++ = *src++; + ;;;; CF = nextbit() + .db #0x0DD,#0x7D ; LD A, IXL + add a, a + jr Z, L2bloop1_0 ; ran out of bits: load new byte + .db #0x0DD,#0x6F ; LD IXL,A + ; bit now in C flag + jr NC, L2bloop1_end ; nextbit()==0, end loop ; STAT +L2bloop1_work: + ; nextbit() == 1, so *dest++ = *src++; + ld a, (bc) + ld (de), a + inc de + inc bc + jp L2bloop1 +L2bloop1_end: + + + ld hl, #0x1 ;; doffset = 1 + ; doffset lives in HL until further notice! + +L2bloop2a: + add hl, hl + jr C, L2b_term ; terminator found. ; STAT + + ;;;; CF = nextbit() + .db #0x0DD,#0x7D ; LD A, IXL + add a, a + jr Z, L2bloop2a_0 ; ran out of bits: load new byte + .db #0x0DD,#0x6F ; LD IXL,A + ; bit now in C flag + jr NC, L2bloop2a_skip_set ; STAT +L2bloop2a_set: + inc hl ;; doffset++ +L2bloop2a_skip_set: + + ;;;; CF = nextbit() + .db #0x0DD,#0x7D ; LD A, IXL + add a, a + jr Z, L2bloop2b_0 ; ran out of bits: load new byte + .db #0x0DD,#0x6F ; LD IXL,A + ; bit now in C flag + jr NC, L2bloop2a ; if nextbit() loop again ; STAT +L2bloop2b_end: + + + ld a, l + sub #0x2 + or h + jr NZ, L2bjmp3 ; doffset != 2 then jump ; STAT + ld hl, (prev_doffset) ;; doffset = prev_doffset + jp L2bjmp3_end +L2bjmp3: + dec l + dec l + dec l ; hl is doffset again + ld h, l ; *=256, now put something in l + ld a, (bc) + inc bc ;; ilen++ + ld l, a + inc hl ;; doffset++ + ld (prev_doffset),hl +L2bjmp3_end: + + ld (doffset),hl + ; doffset committed to memory. + + + ;;;; CF = nextbit() + .db #0x0DD,#0x7D ; LD A, IXL + add a, a + jr Z, L2bjmp3_0 ; ran out of bits: load new byte + .db #0x0DD,#0x6F ; LD IXL,A +L2bjmp3_r: + ; bit now in C flag + ld hl, #0x0 + jp NC, L2bjmp3_skipset ; STAT + ld l, #0x2 ;; movlen = 1, movlen *= 2 +L2bjmp3_skipset: + + + ;;;; CF = nextbit() + .db #0x0DD,#0x7D ; LD A, IXL + add a, a + jr Z, L2bjmp4_0 ; ran out of bits: load new byte + .db #0x0DD,#0x6F ; LD IXL,A + ; bit now in C flag + jr NC, L2bjmp4_zero ; STAT +L2bjmp4_nonzero: + ; movlen in HL (well, only low 2 L bits have stuff) + inc hl +L2bjmp4_zero: + + + xor a + or l ; movlen == 0? + jr NZ, L2bjmp8_movlen_nonzero ; STAT + + ; so movlen == 0 + inc l ;; movlen = 1 + + +L2bloop6: + add hl, hl ;; movlen *= 2 + + ;;;; CF = nextbit() + .db #0x0DD,#0x7D ; LD A, IXL + add a, a + jr Z, L2bloop6_0 ; ran out of bits: load new byte + .db #0x0DD,#0x6F ; LD IXL,A + ; bit now in C flag + jr NC, L2bloop6_zero ; STAT +L2bloop6_nonzero: + inc hl;(hl) +L2bloop6_zero: + ;;;; CF = nextbit() + .db #0x0DD,#0x7D ; LD A, IXL + add a, a + jr Z, L2bloop7_0 ; ran out of bits: load new byte + .db #0x0DD,#0x6F ; LD IXL,A + ; bit now in C flag + jr NC, L2bloop6 ; go around loop again ; STAT +L2bloop7_nonzero: + ; !!nextbit(), loop broken + inc hl + inc hl + + +L2bjmp8_movlen_nonzero: +L2bjmp8a_0d00_compare: + + push bc + + ld bc, (doffset) ;20 + xor a, a ;4 + sub a, c ;4 + ld a, #0x0D ;7 + sbc a, b ;4 == 42 + + jp NC, L2bjmp9_noadd ; STAT + + ; so (doffset > #0x0d00) + inc hl ;; movlen++ + +L2bjmp9_noadd: + ; movlen is in HL + + ; reshuffle registers to be LDIR-friendly + ;want dest (de) in de + ;want src (de-doffset) in hl + ;want movlen (hl) in bc + + ld b, h ;4 + ld c, l ;4 + ld hl, (doffset) ;20 + + ld a, e ;4 + sub l ;4 + ld l, a ;4 + ld a, d ;4 + sbc a, h ;4 + ld h, a ;4 == 52 + ; done shuffling. + + ldi + inc bc + ldir + + pop bc + + jp L2bmain + + +L2b_end: +; ld a, 4 ;DEBUG +; out (254), a ;DEBUG + ret + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; out-of-line jumps +L2bloop7_0: + ;;;; bb = *src, src++ + ld a, (bc) ; get *src + inc bc ; src++ + scf + rla ; ADM: could use undoc''d SLL + .db #0x0DD,#0x6F ; LD IXL,A + + jr NC, L2bloop6 + jp L2bloop7_nonzero + + +L2bloop6_0: + ;;;; bb = *src, src++ + ld a, (bc) ; get *src + inc bc ; src++ + scf + rla ; ADM: could use undoc''d SLL + .db #0x0DD,#0x6F ; LD IXL,A + + jr NC, L2bloop6_zero + jp L2bloop6_nonzero + + +L2bjmp4_0: + ;;;; bb = *src, src++ + ld a, (bc) ; get *src + inc bc ; src++ + scf + rla ; ADM: could use undoc''d SLL + .db #0x0DD,#0x6F ; LD IXL,A + + jr NC, L2bjmp4_zero + jp L2bjmp4_nonzero + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +prev_doffset: .dw #0x0000 +doffset: .dw #0x0000 + +L2b_unpack_ENDSYMBOL: + diff --git a/loader.s b/loader.s new file mode 100644 index 0000000..7ad31ae --- /dev/null +++ b/loader.s @@ -0,0 +1,157 @@ +; +; TAPE LOADER +; + +.include "cpcfirm.inc" +.include "loader.opt" + +loader: + +.ifeq DISK + ; loading from disk + + ld hl, (#0xbe7d) ; save current drive + ld a, (hl) + ld (#drive+1), a +.endif ; end disk code + + ld c, #0xff + ld hl, #start + call mc_start_program + +start: + call kl_rom_walk + +.ifeq DISK +drive: + ld a, #0 ; restore drive + ld hl, (#0xbe7d) + ld (hl), a +.endif ; end disk code + + ld bc, #0 ; set border + call scr_set_border + + ld bc, #0 ; bg color + xor a + call scr_set_ink + + ld a, #1 ; set mode 1 + call scr_set_mode + + ld a, #0xff + call cas_noisy ; disable tape texts + +.ifeq DISK + ; first file is the SCRX + call load_file + +.else ; tape code + + ld ix, #TMP_ADDR + ld de, #SCRX_SIZE + call turboload + +.endif ; end tape code + + ; setup the palette + ld b, #0x10 + xor a + ld ix, #TMP_ADDR + #4 +set_palette_loop: + push bc + push af + ld c, (ix) + inc ix + ld b, c + call scr_set_ink + pop af + pop bc + inc a + djnz set_palette_loop + + ; border is already 0 + + ld hl, #0xc000 ; uncompress into the screen + push hl + ld hl, #TMP_ADDR + #0x14 ; compressed data + push hl + call _ucl_uncompress + pop af + pop af + +.ifeq DISK + + ld hl, #fname_end-#1 + inc (hl) + ; load the code + call load_file + +.else ; tape code + + ld ix, #APP_ADDR + ld de, #APP_SIZE + call turboload + +.endif ; tape code ends + + xor a ; set mode 0 + call scr_set_mode + + ; jp to the app entry point + .db #0xc3 + .dw #APP_EP + +.ifeq DISK + +load_file: + ld hl, #fname + ld b, #fname_end-#fname + + ld de, #0x400 ; temp mem (only used in tape mode) + call cas_in_open + + push de + pop hl + call cas_in_direct + + call cas_in_close + ret + +fname: + .str "MAIN.BI0" +fname_end: + +.else ; tape code + +turboload: + di + ex af, af' + push af + ex af, af' + exx + push de + push bc + push hl + exx + xor a + ld r, a + dec a + call _turboload + jp nc, 0 + exx + pop hl + pop bc + pop de + exx + ex af, af' + pop af + ex af, af' + ei + ret + +.include "turboload.s" +.endif ; end tape code + +.area _DATA + diff --git a/loading.png b/loading.png new file mode 100644 index 0000000..b6b314b Binary files /dev/null and b/loading.png differ diff --git a/main.c b/main.c new file mode 100644 index 0000000..bb32475 --- /dev/null +++ b/main.c @@ -0,0 +1,1794 @@ +/* + The Return of Traxtor (Amstrad CPC) + Copyright (C) 2015 Juan J. Martinez + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ +#include +#include +#include + +#include "ucl.h" +#include "cpcrslib/cpcrslib.h" +#include "cpcrslib/cpcwyzlib.h" +#include "splib.h" + +#define WFRAMES 12 // ~ 25 FPS +#include "int.h" +#include "sound.h" + +// generated +#include "font.h" +#include "menubg.h" +#include "playbg.h" +#include "tiles.h" +#include "tiles_alt.h" +#include "ship.h" +#include "return_mus.h" +#include "board_mus.h" +#include "gameover_mus.h" + +#define KEY_RIGHT 0 +#define KEY_LEFT 1 +#define KEY_BEAM 2 +#define KEY_FIRE 3 +#define KEY_PAUSE 4 +#define KEY_ALT_BEAM 5 +#define KEY_QUIT 14 + +#define BW 7 +#define BH 10 + +#define BLOCK_WILD 7 + +#define BLOCK(x) (x & 0x0f) +#define EFFECT(x) (x >> 4) +#define UPDATE_EFFECT(x, y) ((x & 0x0f) | (y << 4)) + +#define LOCK_GRAVITY 8 +#define TILE_ERASE 16 +#define TILE_MARKER 17 +#define TILE_EXPLO 18 +#define TILE_GRAVITY 14 + +#define K_DELAY 3 + +#define DIRTY_NONE 0 +#define DIRTY_SCORE 1 +#define DIRTY_LEVEL 2 +#define DIRTY_BAY 4 +#define DIRTY_ALL 255 + +#define ENDGAME 25 + +// encrypted endgame text; like anyobe is going to read it from the binary! :D +const uint8_t endgame[] = { + 0xf3, 0x45, 0xfe, 0x20, 0x89, 0x36, 0x9a, 0x44, 0xf3, 0x5e, 0x80, 0x31, + 0x99, 0x22, 0x8e, 0x50, 0xef, 0x5f, 0xe5, 0x11, 0xb8, 0x03, 0xdd, 0x73, + 0xdf, 0x64, 0xcc, 0x73, 0xc4, 0x76, 0xcd, 0x77, 0xa7, 0x53, 0xa7, 0x1f, + 0xae, 0x02, 0xdc, 0x6c, 0xdd, 0x74, 0xa4, 0x74, 0xa4, 0x50, 0xa4, 0x03, + 0xb2, 0x19, 0xc7, 0x78, 0xd4, 0x6f, 0xb1, 0x0e, 0xd0, 0x62, 0xd9, 0x60, + 0xdb, 0x6b, 0xd1, 0x0e, 0xfa, 0x0e, 0xa4, 0x12, 0xad, 0x1d, 0xa8, 0x05, + 0xdb, 0x63, 0xd2, 0x7e, 0xa0, 0x0e, 0xbc, 0x03, 0xa4, 0x13, 0xa3, 0x1a, + 0xee, 0x44, 0xf2, 0x49, 0x97, 0x2e, 0x91, 0x22, 0x99, 0x49, 0xb7 +}; + +/* +"THE WAR IS OVER AND\n" +"WE PREVAILED.\n\n" +"FOR NOW...\n\n" +"YOU ARE A LEGEND!\n\n" +"THANKS FOR PLAYING\n" +"THE GAME." +*/ + +// conf +uint8_t conf_mode = 0; // normal, 1: easy +uint8_t conf_tiles = 0; // classic, 1: alternative +uint8_t conf_music = 1; // on, 0: off +uint8_t (*tiles_blocks)[54] = tiles; + +uint8_t dirty_hud; +uint8_t last_wild; +uint8_t dirty_marker; + +#define EFFECTS_DELAY 3 +uint8_t has_effects; +uint8_t effects_delay; +uint8_t combo_delay; + +#define GRAVITY_DELAY 2 +uint8_t gravity[BW * BH * 2]; +uint8_t has_gravity; +uint8_t gravity_delay; + +uint8_t empty_board; +uint8_t gameover; +uint8_t paused; +uint16_t score; +uint16_t hiscore = 0; +uint8_t level; + +int16_t next_level; +int16_t next_line; +int16_t next_line_level; + +uint8_t px; +uint8_t py; +uint8_t old_px; + +int8_t board[BW * BH]; + +uint8_t bay[3]; +int8_t bay_top; + +const uint8_t pal_hw[] = { + 0x54, 0x44, 0x55, 0x5c, 0x58, 0x4c, 0x4d, 0x46, + 0x57, 0x40, 0x5f, 0x4e, 0x5a, 0x5b, 0x4a, 0x4b +}; + +uint8_t joystick; +const uint16_t key_map[2][6] = { + // right, left, beam, fire, pause, extra beam + { 0x4002, 0x4101, 0x4004, 0x4580, 0x4510, 0x0000 }, // keyboard + { 0x4908, 0x4904, 0x4580, 0x4910, 0x4510, 0x4920 } // joystick +}; +const char redefine[5][6] = { + "RIGHT", "LEFT ", "BEAM ", "FIRE ", "PAUSE" +}; + +void +map_keys() +{ + uint8_t i; + + for (i = 0; i < 6; i++) + cpc_AssignKey(i, key_map[joystick][i]); +} + +void +draw_controls() +{ + if (joystick) + { + cpc_SetInkGphStr(2, 170); + cpc_SetInkGphStr(3, 42); + } + else + { + cpc_SetInkGphStr(2, 160); + cpc_SetInkGphStr(3, 138); + } + cpc_PrintGphStrXY("1:JOYSTICK", 30, 80); + + if (joystick) + { + cpc_SetInkGphStr(2, 160); + cpc_SetInkGphStr(3, 138); + } + else + { + cpc_SetInkGphStr(2, 170); + cpc_SetInkGphStr(3, 42); + } + cpc_PrintGphStrXY("2:KEYBOARD", 30, 90); + + cpc_SetInkGphStr(2, 160); + cpc_SetInkGphStr(3, 138); + cpc_PrintGphStrXY("3:REDEFINE", 30, 100); + + cpc_PrintGphStrXY("4:OPTIONS", 30, 110); + + cpc_SetInkGphStr(2, 128); + cpc_SetInkGphStr(3, 128); + cpc_PrintGphStrXY("BEAM OR FIRE TO PLAY", 20, 135); +} + +void +draw_menu() +{ + uint8_t buffer[11] = "HI: "; + + // colors: 0 bg, 1 unused, 2 top/bottom, 3 center + // + // 8: blue + // 42: yellow + // 138: orange + // 160: red + // 32: dark purple + // 40: light purple + // 170: white + // 162: light blue + // + + ucl_uncompress(menubg, (uint8_t *)BUFF_ADDR); + + wait_vsync(); + cpc_PutSp((char *)BUFF_ADDR, 56, 80, (int)0xf050); + draw_controls(); + + if (hiscore > 0) + { + cpc_SetInkGphStr(2, 162); + cpc_SetInkGphStr(3, 170); + pad_numbers(buffer + 4, 6, hiscore); + cpc_PrintGphStrXY(buffer, 30, 0); + } + + cpc_SetInkGphStr(2, 160); + cpc_SetInkGphStr(3, 40); + cpc_PrintGphStrXY("CODE, GRAPHICS & SOUND", 18, 160); + + cpc_SetInkGphStr(2, 32); + cpc_SetInkGphStr(3, 32); + cpc_PrintGphStrXY("JUAN J. MARTINEZ", 24, 170); + + cpc_SetInkGphStr(2, 8); + cpc_SetInkGphStr(3, 8); + cpc_PrintGphStrXY("\x1f""2015 USEBOX.NET", 24, 190); +} + +void +run_redefine() +{ + uint8_t i; + + memset((uint8_t *)BUFF_ADDR, 0, 65 * 80); + cpc_PutSp((char *)BUFF_ADDR, 65, 80, (int)0xc320); + + // be sure the keyboard is free + while (cpc_AnyKeyPressed()) + wait(); + + cpc_SetInkGphStr(2, 160); + cpc_SetInkGphStr(3, 138); + cpc_PrintGphStrXY("PRESS KEY FOR:", 20, 110); + + cpc_SetInkGphStr(2, 42); + cpc_SetInkGphStr(3, 42); + + // clean exiting keys + for (i = 0; i < 6; i++) + cpc_AssignKey(i, (int)0xffff); + + for (i = 0; i < 5; i++) + { + wait_vsync(); + cpc_PrintGphStrXY(redefine[i], 50, 110); + cpc_RedefineKey(i); + } + + // alt beam + cpc_AssignKey(i, (int)0x0000); + + // be sure the keyboard is free + while (cpc_AnyKeyPressed()) + wait(); + + cpc_PutSp((char *)BUFF_ADDR, 65, 80, (int)0xc320); +} + +uint8_t song_names[5][11] = +{ + { "THE RETURN" }, + { "THE LEGEND" }, + { "I REMEMBER" }, + { "FULL BOARD" }, + { "GAME OVER " } +}; + +const uint8_t *juke_songs[] = { return_mus, 0, 0, board_mus, gameover_mus }; + +void +draw_options(uint8_t song) +{ + cpc_SetInkGphStr(2, 160); + cpc_SetInkGphStr(3, 138); + + wait_vsync(); + cpc_PrintGphStrXY("ESC:MAIN MENU", 22, 125); + + if (conf_mode) + cpc_PrintGphStrXY("1:EASY MODE ", 26, 80); + else + cpc_PrintGphStrXY("1:NORMAL MODE", 26, 80); + + if (conf_tiles) + cpc_PrintGphStrXY("2:ALT TILES ", 26, 90); + else + cpc_PrintGphStrXY("2:CLASSIC TILES", 26, 90); + + if (conf_music) + cpc_PrintGphStrXY("3:MUSIC ON ", 26, 100); + else + cpc_PrintGphStrXY("3:MUSIC OFF", 26, 100); + + cpc_PrintGphStrXY("4:JUKEBOX [", 26, 110); + cpc_PrintGphStrXY("]", 68, 110); + + cpc_SetInkGphStr(2, 162); + cpc_SetInkGphStr(3, 170); + cpc_PrintGphStrXY(song_names[song], 48, 110); +} + +void +run_options() +{ + uint8_t song = 0, k_delay = 0; + + memset((uint8_t *)BUFF_ADDR, 0, 65 * 80); + cpc_PutSp((char *)BUFF_ADDR, 65, 80, (int)0xc320); + + // be sure the keyboard is free + while (cpc_AnyKeyPressed()) + wait(); + + draw_options(song); + + while (1) + { + cpc_ScanKeyboard(); + + if (k_delay) + { + k_delay--; + continue; + } + + if (cpc_TestKeyF(KEY_QUIT)) + break; + + if (cpc_TestKeyF(8)) // key: 1 + { + conf_mode = !conf_mode; + + draw_options(song); + k_delay = 8; + continue; + } + + if (cpc_TestKeyF(9)) // key: 2 + { + conf_tiles = !conf_tiles; + + if (conf_tiles) + tiles_blocks = (uint8_t *[])tiles_alt; + else + tiles_blocks = (uint8_t *[])tiles; + + draw_options(song); + k_delay = 8; + continue; + } + + if (cpc_TestKeyF(10)) // key: 3 + { + conf_music = !conf_music; + + draw_options(song); + k_delay = 8; + continue; + } + + if (cpc_TestKeyF(11)) // key: 4 + { + song++; + if (song > 4) + song = 0; + + WyzPlayerOff(); + switch (song) + { + default: + ucl_uncompress(juke_songs[song], (uint8_t *)7000); + cpc_WyzLoadSong(0); + break; + case 1: + case 2: + cpc_WyzLoadSong(song); + break; + } + WyzPlayerOn(); + + draw_options(song); + k_delay = 8; + continue; + } + } + + // be sure the keyboard is free + while (cpc_AnyKeyPressed()) + wait(); + + if (song) + { + WyzPlayerOff(); + ucl_uncompress(return_mus, (uint8_t *)7000); + cpc_WyzLoadSong(0); + WyzPlayerOn(); + } + + cpc_PutSp((char *)BUFF_ADDR, 65, 80, (int)0xc320); +} + +void +do_text_fadeout(char * text, uint8_t x, uint8_t y) +{ + cpc_SetInkGphStr(2, 170); + cpc_SetInkGphStr(3, 170); + wait(); + cpc_PrintGphStrXY2X(text, x, y); + + cpc_SetInkGphStr(2, 32); + cpc_SetInkGphStr(3, 32); + wait(); + wait(); + cpc_PrintGphStrXY2X(text, x, y); + + cpc_SetInkGphStr(2, 128); + cpc_SetInkGphStr(3, 128); + wait(); + wait(); + cpc_PrintGphStrXY2X(text, x, y); + + cpc_SetInkGphStr(2, 0); + cpc_SetInkGphStr(3, 0); + wait(); + wait(); + cpc_PrintGphStrXY2X(text, x, y); +} + +void +screen_black() +{ + uint8_t i; + + wait_vsync(); + + // all black + for (i = 0; i < 16; i++) + set_hw_ink(i, 0x54); +} + +void +screen_fadein() +{ + uint8_t i; + + // all blue + wait_vsync(); + for (i = 1; i < 16; i++) + set_hw_ink(i, 0x44); + + for (i = 0; i < 4; i++) + wait(); + + // all white + wait_vsync(); + for (i = 1; i < 16; i++) + set_hw_ink(i, 0x4b); + + for (i = 0; i < 3; i++) + wait(); + + // final colours + wait_vsync(); + for (i = 1; i < 16; i++) + set_hw_ink(i, pal_hw[i]); +} + +const uint8_t text_intro[] = + "1000 YEARS HAVE PASSED SINCE THE\n" + "LAST WAR, WHEN TRAXTOR SAVED US.\n\n" + "WITH THE LEGEND NOW LONG GONE,\n" + "THIS IS A STORY OF ITS LEGACY..."; + +const uint8_t intro_pos[3] = { 0, 3, 6 }; + +void +run_intro() +{ + const uint8_t *pt = text_intro; + uint8_t buffer[2] = { 0, 0 }; + uint8_t i, j, k; + + init_tiles(); + + cpc_WyzLoadSong(2); + WyzPlayerOn(); + + for (k = 0; k < 48; k++) + wait(); + + for (k = 0; k < 3; k++) + { + i = intro_pos[k]; + put_tile(tiles[k * 2], i, 1); + put_tile(tiles[1 + k * 2], i, 2); + + put_tile(tiles[6 + k * 2], i, 14); + put_tile(tiles[7 + k * 2], i, 15); + } + + update_screen(); + screen_fadein(); + + for (k = 0; k < 32; k++) + wait(); + + cpc_SetInkGphStr(2, 162); + cpc_SetInkGphStr(3, 170); + + i = 8; + j = 60; + while (*pt) + { + switch (*pt) + { + default: + buffer[0] = *pt; + cpc_PrintGphStrXY(buffer, i, j); + i += 2; + break; + case '\n': + i = 8; + j += 10; + break; + } + for (k = 0; *pt != ' ' && k < 3; k++) + wait(); + pt++; + + if (cpc_AnyKeyPressed()) + goto exit_intro; + } + + for (k = 0; k < 42; k++) + wait(); + + WyzPlayerOff(); + cpc_WyzConfigurePlayer(0); + WyzPlayerOn(); + cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_EXPLO); + + for (j = 0; j < 4; j++) + { + for (k = 0; k < 3; k++) + { + i = intro_pos[k]; + put_tile(tiles[TILE_EXPLO + 1 + j * 2], i, 1); + put_tile(tiles[TILE_EXPLO + j * 2], i, 2); + } + + for (k = 0; k < 3; k++) + { + i = intro_pos[k]; + put_tile(tiles[TILE_EXPLO + 1 + j * 2], i, 14); + put_tile(tiles[TILE_EXPLO + j * 2], i, 15); + } + + wait(); + update_screen(); + for (i = 0; i < 6; i++) + wait(); + } + + for (k = 0; k < 3; k++) + { + i = intro_pos[k]; + put_tile(tiles[TILE_ERASE], i, 1); + put_tile(tiles[TILE_ERASE], i, 2); + + put_tile(tiles[TILE_ERASE], i, 14); + put_tile(tiles[TILE_ERASE], i, 15); + } + update_screen(); + + for (k = 0; k < 42; k++) + wait(); + +exit_intro: + WyzPlayerOff(); +} + +const uint16_t bay_addr[] = { 0xc360, 0xcbb0, 0xd400, 0xdc50, 0xe4a0, 0xecf0 }; + +void +draw_hud() +{ + int8_t i; + uint8_t buffer[6]; + + cpc_SetInkGphStr(2, 170); + cpc_SetInkGphStr(3, 170); + + if (dirty_hud & DIRTY_SCORE) + { + pad_numbers(buffer, 5, score); + cpc_PrintGphStrXY(buffer, 7, 32); + } + + if (dirty_hud & DIRTY_LEVEL) + { + pad_numbers(buffer, 2, level); + cpc_PrintGphStrXY(buffer, 67, 32); + } + + if (dirty_hud & DIRTY_BAY) + { + for (i = 2; i >= 0; i--) + if (bay[i] == 0) + { + cpc_PutSp(tiles[TILE_ERASE], 9, 6, bay_addr[i * 2]); + cpc_PutSp(tiles[TILE_ERASE], 9, 6, bay_addr[1 + i * 2]); + } + else + { + cpc_PutSp(tiles_blocks[(bay[i] - 1) * 2], 9, 6, bay_addr[i * 2]); + cpc_PutSp(tiles_blocks[1 + (bay[i] - 1) * 2], 9, 6, bay_addr[1 + i * 2]); + } + + } + + dirty_hud = DIRTY_NONE; +} + +const uint16_t ship_addr[] = { 0xdef4, 0xdefa, 0xdf00, 0xdf06, 0xdf0c, 0xdf12, 0xdf18 }; +const uint16_t engine_addr[] = { 0xef94, 0xef9a, 0xefa0, 0xefa6, 0xefac, 0xefb2, 0xefb8 }; +const uint8_t engine_cycle[] = { 3, 2, 3, 2, 1, 2, 1, 0, 1 }; + +uint8_t engine; + +void +draw_ship() +{ + cpc_PutSp(ship[0], 18, 6, ship_addr[px]); + if (engine_cycle[engine]) + cpc_PutSp(&ship[0][126 - (engine_cycle[engine] * 6)], engine_cycle[engine], 6, engine_addr[px]); + + engine++; + if (engine > 8) + engine = 0; + + old_px = px; +} + +void +erase_ship() +{ + if (old_px != px) + cpc_PutSp(ship[1], 21, 6, ship_addr[old_px]); + else + cpc_PutSp(&ship[1][126 - 18], 3, 6, engine_addr[px]); +} + +void +draw_board() +{ + uint8_t i, j; + int8_t c; + + for (j = 0; j < BH; j++) + { + for (i = 0; i < BW; i++) + { + if (EFFECT(board[i + j & BW])) + continue; + + c = BLOCK(board[i + j * BW]) - 1; + + if (c >= 0) + { + put_tile(tiles_blocks[c * 2], i, j * 2); + put_tile(tiles_blocks[1 + c * 2], i, 1 + j * 2); + continue; + } + } + } +} + +int8_t +update_py() +{ + int8_t i; + + for (i = BH - 1; i >= 0; i--) + if (board[px + i * BW]) + break; + + return i; +} + +void +add_board_line() +{ + uint8_t i; + + memmove(board + BW, board, (BW * BH) - BW); + for (i = 0; i < BW; ++i) + { + board[i] = 1 + (rand() % 6); + if (!conf_mode && i > 0 && board[i] == board[i - 1]) + board[i] = 1 + (rand() % 6); + } + + if (!last_wild && (rand() % 4) < 2) + board[rand() % (BW - 1)] = BLOCK_WILD; + + last_wild = last_wild ? 0 : 1; +} + +// used to calculate the matches +uint8_t matches; +int8_t sc_buffer[BW * BH]; + +void +process_matches(uint8_t x, uint8_t y, uint8_t tile, uint8_t *matches) +{ + int8_t i; + + for (i = x - 1; i >= 0; i--) + { + if (!BLOCK(board[i + y * BW])) + break; + if (sc_buffer[i + y * BW] && BLOCK(board[i + y * BW]) == tile) + { + (*matches)++; + sc_buffer[i + y * BW] = 0; + process_matches(i, y, tile, matches); + } + else + break; + } + + for (i = x + 1; i < BW; i++) + { + if (!BLOCK(board[i + y * BW])) + break; + if (sc_buffer[i + y * BW] && BLOCK(board[i + y * BW]) == tile) + { + (*matches)++; + sc_buffer[i + y * BW] = 0; + process_matches(i, y, tile, matches); + } + else + break; + } + + for (i = y - 1; i >= 0; i--) + { + if (!BLOCK(board[x + i * BW])) + break; + if (sc_buffer[x + i * BW] && BLOCK(board[x + i * BW]) == tile) + { + (*matches)++; + sc_buffer[x + i * BW] = 0; + process_matches(x, i, tile, matches); + } + else + break; + } + + for (i = y + 1; i < BH; i++) + { + if (!BLOCK(board[x + i * BW])) + break; + if (sc_buffer[x + i * BW] && BLOCK(board[x + i * BW]) == tile) + { + (*matches)++; + sc_buffer[x + i * BW] = 0; + process_matches(x, i, tile, matches); + } + else + break; + } +} + +uint16_t +has_matches() +{ + uint8_t i; + + memset(sc_buffer, 0, BLOCK_WILD + 1); + + for (i = 0; i < BW * BH; i++) + sc_buffer[BLOCK(board[i])]++; + + for (i = 0; i < 3; i++) + sc_buffer[bay[i]]++; + + for (i = 1; i < 7; i++) + // 3 matches or 2 + wildcard + if (sc_buffer[i] >= 3 || (sc_buffer[i] == 2 && sc_buffer[BLOCK_WILD])) + return 1; + + return 0; +} + +void +draw_effects() +{ + uint8_t i, j, e; + + for (j = 0; j < BH; j++) + for (i = 0; i < BW; i++) + { + e = EFFECT(board[i + j * BW]); + if (e) + { + e--; + put_tile(tiles[TILE_EXPLO + e * 2], i, 1 + j * 2); + put_tile(tiles[TILE_EXPLO + 1 + e * 2], i, j * 2); + } + } +} + +void +add_gravity() +{ + uint8_t i, j; + + for (j = 1; j < BH; j++) + for (i = 0; i < BW; i++) + if (BLOCK(board[i + j * BW]) && !BLOCK(board[i + (j - 1) * BW])) + { + gravity[i + j * 2 * BW] = TILE_GRAVITY; + gravity[i + (1 + (j * 2)) * BW] = TILE_GRAVITY + 1; + board[i + j * BW] = 0; + has_gravity = 1; + } +} + +void +update_effects() +{ + uint8_t i, j, e; + + effects_delay++; + if (effects_delay < EFFECTS_DELAY) + return; + + effects_delay = 0; + + for (j = 0; j < BH; j++) + for (i = 0; i < BW; i++) + { + e = EFFECT(board[i + j * BW]); + if (!e) + continue; + + if (e < 4) + board[i + j * BW] = UPDATE_EFFECT(board[i + j * BW], e + 1); + else + { + board[i + j * BW] = 0; + put_tile(tiles[TILE_ERASE], i, j * 2); + put_tile(tiles[TILE_ERASE], i, 1 + j * 2); + + has_effects--; + if (!has_effects && !gameover) + { + add_gravity(); + + if (!dirty_marker) + { + put_tile(tiles[TILE_ERASE], px, py * 2); + dirty_marker = 1; + } + + // check for empty board + if (!gameover && bay_top == 2) + { + empty_board = 1; + for (i = 0; i < BW * BH; i++) + if (BLOCK(board[i])) + { + empty_board = 0; + break; + } + } + return; + } + } + } +} + +void +erase_gravity() +{ + uint8_t i, j; + + for (j = 0; j < BH * 2; j++) + for (i = 0; i < BW; i++) + if (gravity[i + j * BW] && j < BH * 2 - 1) + put_tile(tiles[TILE_ERASE], i, j); +} + +void +draw_gravity() +{ + uint8_t i, j, c; + + for (j = 0; j < BH * 2; j++) + for (i = 0; i < BW; i++) + { + c = gravity[i + j * BW]; + if (c) + { + if (j < BH * 2 - 1) + put_tile(tiles[c], i, j); + if (j && !BLOCK(board[i + (j >> 1) * BW]) && !gravity[i + (j - 1) * BW]) + put_tile(tiles[TILE_ERASE], i, j - 1); + } + } +} + +void +update_gravity() +{ + uint8_t i; + + gravity_delay++; + if (gravity_delay < GRAVITY_DELAY) + return; + + gravity_delay = 0; + has_gravity = 0; + + memmove(gravity + BW, gravity, (BW * BH * 2) - BW); + memset(gravity, 0, BW); + + for (i = BW; i < BW * BH * 2; i++) + if (gravity[i]) + { + has_gravity = 1; + return; + } +} + +void +level_up() +{ + level++; + next_level = 24 + 3 * (int16_t)level; + + if (conf_mode) // easy + next_line_level -= 16; + else + next_line_level -= 32; + + if (level % 5 == 0) + next_line_level += 84; + if (next_line_level < 64) + next_line_level = 64; + + dirty_hud |= DIRTY_LEVEL; +} + +void +dec_engame() +{ + uint8_t i = 21, j = 70, k; + uint8_t p = 0x59, key = 0xfe, c; + const uint8_t *pt = endgame; + uint8_t buffer[2] = { 0, 0}; + + while (1) + { + c = (*pt ^ key) ^ p; + if (!c) + break; + + switch (c) + { + default: + buffer[0] = c; + cpc_PrintGphStrXY(buffer, i, j); + for (k = 0; c != ' ' && k < 3; k++) + { + wait(); + erase_ship(); + draw_ship(); + } + i += 2; + break; + case '\n': + i = 21; + j += 10; + break; + } + p = *pt; + pt++; + } +} + +void +run_play() +{ + uint8_t i, j, c, k_delay = 0; + int8_t h; + + srand(tick); + cpc_WyzConfigurePlayer(0); + WyzPlayerOn(); + + init_tiles(); + + memset(board, 0, BW * BH); + + // frequency of the wildcards + last_wild = 0; + + has_effects = 0; + effects_delay = 0; + combo_delay = 0; + + has_gravity = 0; + gravity_delay = 0; + + empty_board = 0; + gameover = 0; + paused = 0; + score = 0; + level = 1; + next_level = 15; + next_line = 0; + next_line_level = 336; + + px = 3; + old_px = 3; + py = 0; + engine = 0; + + bay_top = 2; + memset(bay, 0, 3); + + add_board_line(); + add_board_line(); + draw_board(); + + py = 1 + update_py(); + put_tile(tiles[TILE_MARKER], px, py * 2); + dirty_marker = 0; + + screen_black(); + + wait_vsync(); + ucl_uncompress(playbg, (uint8_t *)0xc000); + update_screen(); + + if (conf_mode) // easy + { + cpc_SetInkGphStr(2, 8); + cpc_SetInkGphStr(3, 8); + cpc_PrintGphStrXY("EASY", 0, 190); + } + + dirty_hud = DIRTY_ALL; + draw_hud(); + + draw_ship(); + + cpc_SetInkGphStr(2, 138); + cpc_SetInkGphStr(3, 42); + cpc_PrintGphStrXY2X("READY?", 35, 90); + + screen_fadein(); + + cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_READY); + for (i = 0; i < 58; i++) + { + wait(); + erase_ship(); + draw_ship(); + } + + do_text_fadeout("READY?", 35, 90); + + if (conf_music) + { + WyzPlayerOff(); + cpc_WyzLoadSong(1); + WyzPlayerOn(); + } + + while (1) + { + cpc_ScanKeyboard(); + + if (cpc_TestKeyF(KEY_QUIT)) + break; + + if (!k_delay) + { + if (cpc_TestKeyF(KEY_PAUSE)) + { + if (!paused) + { + memset((uint8_t *)BUFF_ADDR, 0, TMW * TMH * TH * TW / 2); + for (j = 0; j < TMH - 1; j++) + for (i = 0; i < TMW; i++) + invalidate_tile_xy(i, j); + + wait(); + update_screen(); + + cpc_SetInkGphStr(2, 138); + cpc_SetInkGphStr(3, 42); + cpc_PrintGphStrXY2X("PAUSED", 35, 80); + + if (conf_music) + { + WyzPlayerOff(); + cpc_WyzConfigurePlayer(0); + WyzPlayerOn(); + } + + cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_ERROR); + paused = 1; + + } + else + { + do_text_fadeout("PAUSED", 35, 80); + + draw_board(); + if (has_effects) + draw_effects(); + if (has_gravity) + draw_gravity(); + + put_tile(tiles[TILE_MARKER], px, py * 2); + dirty_marker = 0; + + wait(); + update_screen(); + + paused = 0; + + if (conf_music) + { + WyzPlayerOff(); + cpc_WyzLoadSong(1); + WyzPlayerOn(); + } + } + + k_delay = K_DELAY; + continue; + } + + if (paused) + goto skip_controls; + + if (cpc_TestKeyF(KEY_RIGHT) && !cpc_TestKeyF(KEY_LEFT)) + { + if (px < BW - 1) + { + put_tile(tiles[TILE_ERASE], px, py * 2); + px++; + dirty_marker = 1; + } + + k_delay = K_DELAY; + } + + if (cpc_TestKeyF(KEY_LEFT) && !cpc_TestKeyF(KEY_RIGHT)) + { + if (px > 0) + { + put_tile(tiles[TILE_ERASE], px, py * 2); + px--; + dirty_marker = 1; + } + + k_delay = K_DELAY; + } + + if ((cpc_TestKeyF(KEY_BEAM) || cpc_TestKeyF(KEY_ALT_BEAM)) + && !cpc_TestKeyF(KEY_FIRE)) + { + if (bay_top >= 0) + { + h = update_py(); + + if (h >= 0 && !EFFECT(board[px + h * BW])) + { + bay[bay_top--] = board[px + h * BW]; + board[px + h * BW] = 0; + + put_tile(tiles[TILE_ERASE], px, h * 2); + put_tile(tiles[TILE_ERASE], px, 1 + h * 2); + + if (!dirty_marker) + { + put_tile(tiles[TILE_ERASE], px, py * 2); + dirty_marker = 1; + } + + dirty_hud |= DIRTY_BAY; + } + else + cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_ERROR); + } + else + cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_ERROR); + + k_delay = K_DELAY; + } + + if (cpc_TestKeyF(KEY_FIRE) && !cpc_TestKeyF(KEY_BEAM) + && !cpc_TestKeyF(KEY_ALT_BEAM)) + { + if (bay_top < 2) + { + h = update_py(); + + if (h == BH - 2) + { + k_delay = K_DELAY; + cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_ERROR); + continue; + } + + // change wildcard to target block + if (BLOCK(bay[bay_top + 1]) == BLOCK_WILD + && h >= 0 && BLOCK(board[px + h * BW])) + bay[bay_top + 1] = BLOCK(board[px + h * BW]); + + h++; + bay_top++; + board[px + h * BW] = bay[bay_top]; + c = bay[bay_top]; + bay[bay_top] = 0; + dirty_hud |= DIRTY_BAY; + + matches = 0; + memset(sc_buffer, 1, BW * BH); + process_matches(px, h, c, &matches); + + // 3 matches and not targeting a wildcard! + if (matches >= 3 && BLOCK(board[px + h * BW]) != BLOCK_WILD) + { + next_level -= matches; + + for (j = 0; j < BH; j++) + for (i = 0; i < BW; i++) + { + if (!sc_buffer[i + j * BW]) + { + if (EFFECT(board[i + j * BW])) + { + cpc_SetInkGphStr(2, 138); + cpc_SetInkGphStr(3, 42); + + cpc_PrintGphStrXY("COMBO!", 6, 52); + combo_delay = 32; + } + else + has_effects++; + board[i + j * BW] = UPDATE_EFFECT(board[i + j * BW], 1); + cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_EXPLO); + } + } + + score += matches * 5; + if (matches > 3) + score += (matches - 3) * 10; + + dirty_hud |= DIRTY_SCORE; + + if (score > hiscore) + hiscore = score; + } + else + { + c--; + // draw only the changed tile + put_tile(tiles_blocks[c * 2], px, h * 2); + put_tile(tiles_blocks[1 + c * 2], px, 1 + h * 2); + } + + // will update marker + dirty_marker = 1; + } + else + cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_ERROR); + + k_delay = K_DELAY; + } + } + else + k_delay--; + +skip_controls: + if (!paused && has_effects) + { + update_effects(); + draw_effects(); + } + + if (!paused && has_gravity) + { + update_gravity(); + draw_gravity(); + } + + if (dirty_marker) + { + py = 1 + update_py(); + put_tile(tiles[TILE_MARKER], px, py * 2); + dirty_marker = 0; + } + + wait(); + update_screen(); + erase_ship(); + draw_ship(); + draw_hud(); + + if (paused) + continue; + + if (combo_delay) + { + combo_delay--; + if (!combo_delay) + cpc_PrintGphStrXY(" ", 6, 52); + } + + if (empty_board) + { + if (conf_music) + { + WyzPlayerOff(); + cpc_WyzConfigurePlayer(0); + WyzPlayerOn(); + } + + while (has_gravity) + { + update_gravity(); + draw_gravity(); + wait(); + update_screen(); + erase_ship(); + draw_ship(); + } + + if (combo_delay) + { + combo_delay = 0; + cpc_PrintGphStrXY(" ", 6, 52); + } + + dirty_hud = DIRTY_ALL; + draw_hud(); + + memset((uint8_t *)BUFF_ADDR, 0, TMW * TMH * TH * TW / 2); + for (j = 0; j < TMH - 1; j++) + for (i = 0; i < TMW; i++) + invalidate_tile_xy(i, j); + + wait(); + update_screen(); + + px = 3; + + WyzPlayerOff(); + ucl_uncompress(board_mus, (uint8_t *)7000); + cpc_WyzLoadSong(0); + WyzPlayerOn(); + + cpc_SetInkGphStr(2, 138); + cpc_SetInkGphStr(3, 42); + cpc_PrintGphStrXY2X("FULL BOARD", 31, 60); + for (i = 0; i < 72; i++) + { + wait(); + erase_ship(); + draw_ship(); + } + + WyzPlayerOff(); + WyzPlayerOn(); + + cpc_SetInkGphStr(2, 160); + cpc_SetInkGphStr(3, 40); + cpc_PrintGphStrXY("LINES", 31, 85); + i = 0; + if (next_level > 0) + i += next_level * 10; + score += i; + pad_numbers((uint8_t *)BUFF_ADDR, 4, i); + cpc_PrintGphStrXY((char *)BUFF_ADDR, 31 + 12, 85); + + dirty_hud = DIRTY_SCORE; + draw_hud(); + + if (i == 0) + cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_ERROR); + else + cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_LEVEL); + + for (i = 0; i < 46; i++) + { + wait(); + erase_ship(); + draw_ship(); + } + + score += 2500; + cpc_SetInkGphStr(2, 160); + cpc_SetInkGphStr(3, 40); + cpc_PrintGphStrXY("EXTRA 2500", 31, 95); + + dirty_hud = DIRTY_SCORE; + draw_hud(); + + cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_LEVEL); + for (i = 0; i < 46; i++) + { + wait(); + erase_ship(); + draw_ship(); + } + + cpc_SetInkGphStr(2, 42); + cpc_SetInkGphStr(3, 170); + cpc_PrintGphStrXY("LEVEL UP!", 31, 115); + + level_up(); + draw_hud(); + + cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_LEVEL); + for (i = 0; i < 46; i++) + { + wait(); + erase_ship(); + draw_ship(); + } + + memset((uint8_t *)BUFF_ADDR, 0, TMW * TMH * TH * TW / 2); + for (j = 0; j < TMH - 1; j++) + for (i = 0; i < TMW; i++) + invalidate_tile_xy(i, j); + + wait(); + update_screen(); + + next_line = 0; + add_board_line(); + add_board_line(); + draw_board(); + + py = 1 + update_py(); + put_tile(tiles[TILE_MARKER], px, py * 2); + dirty_marker = 0; + + wait(); + update_screen(); + + cpc_SetInkGphStr(2, 138); + cpc_SetInkGphStr(3, 42); + cpc_PrintGphStrXY2X("READY?", 35, 90); + + cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_READY); + for (i = 0; i < 58; i++) + { + wait(); + erase_ship(); + draw_ship(); + } + + do_text_fadeout("READY?", 35, 90); + + if (conf_music) + { + WyzPlayerOff(); + cpc_WyzLoadSong(1); + WyzPlayerOn(); + } + + if (score > hiscore) + hiscore = score; + + empty_board = 0; + continue; + } + + if (++next_line > next_line_level || !has_matches()) + { + next_line = 0; + add_board_line(); + cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_LINE); + + if (has_gravity) + { + update_gravity(); + update_gravity(); + draw_gravity(); + } + + draw_board(); + + for (i = 0; i < BW; i++) + if (board[i + (BH - 1) * BW] != 0) + { + if (conf_music) + { + WyzPlayerOff(); + cpc_WyzConfigurePlayer(0); + WyzPlayerOn(); + } + + update_screen(); + gameover = 1; + + bay_top = 2; + memset(bay, 0, 3); + dirty_hud |= DIRTY_BAY; + draw_hud(); + + // hacky! + memset((uint8_t *)BUFF_ADDR, 0, TMW * TMH * TH * TW / 2); + for (i = 0; i < BW; i++) + invalidate_tile_xy(i, TMH - 1); + + wait(); + cpc_PutSp(ship[1], 21, 6, ship_addr[px]); + update_screen(); + + erase_gravity(); + put_tile(tiles[TILE_ERASE], px, py * 2); + draw_board(); + wait(); + update_screen(); + + for (j = 0; j < BH; j++) + { + for (i = 0; i < BW; i++) + if (BLOCK(board[i + (BH - 1 - j) * BW]) + && !EFFECT(board[i + (BH - 1 - j) * BW])) + { + board[i + (BH - 1 - j) * BW] = UPDATE_EFFECT(1, 1); + has_effects++; + } + + cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_EXPLO); + while (has_effects) + { + update_effects(); + draw_effects(); + update_screen(); + } + } + + cpc_SetInkGphStr(2, 138); + cpc_SetInkGphStr(3, 42); + cpc_PrintGphStrXY2X("GAME OVER", 31, 80); + + WyzPlayerOff(); + ucl_uncompress(gameover_mus, (uint8_t *)7000); + cpc_WyzLoadSong(0); + WyzPlayerOn(); + + for (i = 0; i < 118; i++) + wait(); + + WyzPlayerOff(); + + for (i = 0; i < 24; i++) + wait(); + + do_text_fadeout("GAME OVER", 31, 80); + break; + } + + if (gameover) + break; + + py = 1 + update_py(); + put_tile(tiles[TILE_MARKER], px, py * 2); + dirty_marker = 0; + + wait(); + update_screen(); + } + + if (!has_effects && next_level <= 0) + { + cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_LEVEL); + level_up(); + + if (level > ENDGAME) + { + gameover = 1; + bay_top = 2; + memset(bay, 0, 3); + dirty_hud |= DIRTY_BAY; + draw_hud(); + + erase_gravity(); + put_tile(tiles[TILE_ERASE], px, py * 2); + draw_board(); + wait(); + update_screen(); + + px = 3; + + for (j = 0; j < BH; j++) + { + for (i = 0; i < BW; i++) + if (BLOCK(board[i + (BH - 1 - j) * BW]) + && !EFFECT(board[i + (BH - 1 - j) * BW])) + { + board[i + (BH - 1 - j) * BW] = UPDATE_EFFECT(1, 1); + has_effects++; + } + + cpc_WyzStartEffect(WYZ_EFX_CHAN, SND_EXPLO); + while (has_effects) + { + update_effects(); + draw_effects(); + update_screen(); + erase_ship(); + draw_ship(); + } + } + + cpc_SetInkGphStr(2, 138); + cpc_SetInkGphStr(3, 42); + cpc_PrintGphStrXY2X("WELL DONE!", 31, 35); + + WyzPlayerOff(); + ucl_uncompress(return_mus, (uint8_t *)7000); + cpc_WyzLoadSong(0); + WyzPlayerOn(); + + cpc_SetInkGphStr(2, 162); + cpc_SetInkGphStr(3, 170); + dec_engame(); + + // be sure the keyboard is free + while (cpc_AnyKeyPressed()) + wait(); + + while (!cpc_AnyKeyPressed()) + { + wait(); + erase_ship(); + draw_ship(); + } + + wait_vsync(); + cpc_ClrScr(); + + break; + } + } + } + + WyzPlayerOff(); + + wait_vsync(); + cpc_ClrScr(); +} + +const uint8_t text_cycle[] = { 0x4b, 0x4a, 0x47, 0x4e, 0x4c, 0x4e, 0x47, 0x4a }; + +int +main() +{ + uint8_t cycle = 0; + + setup_int(); + + // black + set_hw_border(0x54); + set_hw_ink(0, 0x54); + + cpc_WyzInitPlayer(wyz_sound_table, wyz_ins_table, wyz_effect_table, wyz_song_table); + cpc_WyzConfigurePlayer(0); + + cpc_SetFont(31, font); + + joystick = 1; + map_keys(); + cpc_AssignKey(KEY_QUIT, 0x4804); // ESC + cpc_AssignKey(8, 0x4801); // 1 + cpc_AssignKey(9, 0x4802); // 2 + cpc_AssignKey(10, 0x4702); // 3 + cpc_AssignKey(11, 0x4701); // 4 + + cpc_SetInkGphStr(0, 0); + + screen_black(); + cpc_ClrScr(); + run_intro(); + + screen_black(); + cpc_ClrScr(); + draw_menu(); + screen_fadein(); + + ucl_uncompress(return_mus, (uint8_t *)7000); + cpc_WyzLoadSong(0); + WyzPlayerOn(); + + while (1) + { + cpc_ScanKeyboard(); + + if (cpc_TestKeyF(8) && !cpc_TestKeyF(9) && !joystick) // key: 1 + { + joystick = 1; + wait_vsync(); + draw_controls(); + + map_keys(); + continue; + } + + if (cpc_TestKeyF(9) && !cpc_TestKeyF(8) && joystick) // key: 2 + { + joystick = 0; + wait_vsync(); + draw_controls(); + + map_keys(); + continue; + } + + if (cpc_TestKeyF(10)) // key: 3 + { + run_redefine(); + + joystick = 0; + draw_controls(); + continue; + } + + if (cpc_TestKeyF(11)) // key: 4 + { + run_options(); + + draw_controls(); + continue; + } + + if (cpc_TestKey(KEY_FIRE) || cpc_TestKey(KEY_BEAM)) // fire + { + // clean the cycle + set_hw_ink(1, 0x44); + WyzPlayerOff(); + + run_play(); + + screen_black(); + draw_menu(); + screen_fadein(); + + ucl_uncompress(return_mus, (uint8_t *)7000); + cpc_WyzLoadSong(0); + WyzPlayerOn(); + } + + wait(); + if (++cycle > 7) + cycle = 0; + set_hw_ink(1, text_cycle[cycle]); + } +} diff --git a/menu.png b/menu.png new file mode 100644 index 0000000..792862f Binary files /dev/null and b/menu.png differ diff --git a/mock.png b/mock.png new file mode 100644 index 0000000..d460bec Binary files /dev/null and b/mock.png differ diff --git a/music/board.mus b/music/board.mus new file mode 100644 index 0000000..b8b9039 Binary files /dev/null and b/music/board.mus differ diff --git a/music/gameover.mus b/music/gameover.mus new file mode 100644 index 0000000..d6d20ab Binary files /dev/null and b/music/gameover.mus differ diff --git a/music/intro.mus b/music/intro.mus new file mode 100644 index 0000000..0c66482 Binary files /dev/null and b/music/intro.mus differ diff --git a/music/return.mus b/music/return.mus new file mode 100644 index 0000000..0e4caac Binary files /dev/null and b/music/return.mus differ diff --git a/music/theplayer.mus b/music/theplayer.mus new file mode 100644 index 0000000..caf2703 Binary files /dev/null and b/music/theplayer.mus differ diff --git a/play.png b/play.png new file mode 100644 index 0000000..afb7531 Binary files /dev/null and b/play.png differ diff --git a/ship.png b/ship.png new file mode 100644 index 0000000..728d934 Binary files /dev/null and b/ship.png differ diff --git a/sound.c b/sound.c new file mode 100644 index 0000000..aacdd22 --- /dev/null +++ b/sound.c @@ -0,0 +1,40 @@ +/* + The Return of Traxtor (Amstrad CPC) + Copyright (C) 2015 Juan J. Martinez + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ +#include + +#include "theplayer_mus.h" +#include "intro_mus.h" + +const uint8_t effect0[] = { 0xc2, 0x0e, 0xc2, 0x0e, 0x61, 0x0d, 0x61, 0x0d, 0x23, 0x1c, 0x23, 0x1c, 0xc2, 0x0c, 0xc2, 0x0c, 0x61, 0x0b, 0x61, 0x0b, 0x23, 0x1b, 0x23, 0x1b, 0xc2, 0x0a, 0xc2, 0x0a, 0x61, 0x0a, 0x61, 0x0a, 0x23, 0x19, 0x23, 0x19, 0xc2, 0x09, 0xc2, 0x09, 0x61, 0x08, 0x61, 0x08, 0x23, 0x18, 0x23, 0x18, 0xc2, 0x07, 0xc2, 0x07, 0x61, 0x07, 0x61, 0x07, 0x23, 0x16, 0x23, 0x16, 0xc2, 0x06, 0xc2, 0x06, 0x61, 0x05, 0x61, 0x05, 0x23, 0x15, 0x23, 0x15, 0xc2, 0x04, 0xc2, 0x04, 0x61, 0x04, 0x61, 0x04, 0x23, 0x13, 0x23, 0x13, 0xc2, 0x03, 0xc2, 0x03, 0x61, 0x02, 0x61, 0x02, 0x23, 0x12, 0x23, 0x12, 0xc2, 0x01, 0xc2, 0x01, 0xff }; +const uint8_t effect1[] = { 0x20, 0x9e, 0x50, 0x7e, 0xb6, 0x4e, 0x3d, 0x2d, 0xdb, 0x4d, 0x48, 0x6b, 0xd5, 0x8a, 0xff }; +const uint8_t effect2[] = { 0x0c, 0x1a, 0x94, 0x1a, 0x0c, 0x1a, 0x94, 0x1a, 0x0c, 0x1a, 0x94, 0x1a, 0xff }; +const uint8_t effect3[] = { 0x68, 0x0d, 0x72, 0x0c, 0x7c, 0x0b, 0x5e, 0x0a, 0x68, 0x09, 0x72, 0x08, 0x7c, 0x07, 0x5e, 0x06, 0x68, 0x05, 0x72, 0x04, 0x7c, 0x03, 0x5e, 0x02, 0xff }; +const uint8_t effect4[] = { 0x0c, 0x2b, 0x94, 0x2b, 0x0c, 0x28, 0x94, 0x28, 0x0c, 0x26, 0x94, 0x26, 0xff }; +const uint8_t *wyz_effect_table[] = { effect0, effect1, effect2, effect3, effect4 }; + +const uint8_t ins0[] = { 14, 0, 11, 0, 10, 0, 129 }; // bass +const uint8_t ins1[] = { 13, 0, 11, 0, 41, 0, 9, 0, 73, 0, 9, 0, 132 }; // lead +const uint8_t ins2[] = { 13, 0, 9, 0, 5, 0, 129 }; // bass low vol +const uint8_t *wyz_ins_table[] = { ins0, ins1, ins2 }; + +const uint8_t sound0[] = { 189, 14, 31, 146, 9, 31, 255 }; +const uint8_t sound1[] = { 9, 110, 0, 30, 122, 0, 255 }; +const uint8_t sound2[] = { 194, 62, 1, 76, 92, 1, 255 }; +const uint8_t *wyz_sound_table[] = { sound0, sound1, sound2 }; + +const uint8_t *wyz_song_table[] = { (const uint8_t *)7000, theplayer_mus, intro_mus }; diff --git a/sound.h b/sound.h new file mode 100644 index 0000000..2fce1dd --- /dev/null +++ b/sound.h @@ -0,0 +1,36 @@ +/* + The Return of Traxtor (Amstrad CPC) + Copyright (C) 2015 Juan J. Martinez + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ +#ifndef _SOUND_H +#define _SOUND_H + +// effect definitions + +#define SND_READY 0 +#define SND_EXPLO 1 +#define SND_ERROR 2 +#define SND_LEVEL 3 +#define SND_LINE 4 + +#define WYZ_EFX_CHAN 2 + +extern const uint8_t *wyz_effect_table[]; +extern const uint8_t *wyz_ins_table[]; +extern const uint8_t *wyz_sound_table[]; +extern const uint8_t *wyz_song_table[]; + +#endif // _SOUND_H diff --git a/splib.c b/splib.c new file mode 100644 index 0000000..400ca16 --- /dev/null +++ b/splib.c @@ -0,0 +1,325 @@ +/* + The Return of Traxtor (Amstrad CPC) + Copyright (C) 2015 Juan J. Martinez + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ +#include + +#include "splib.h" + +static struct st_tile tiles[TMW * TMH]; +struct st_tile *dirty, *last_dirty; + +#define T_CLEAN 0 +#define T_DIRTY 1 + +// faster +struct st_tile *tile_p; + +void +pad_numbers(uint8_t *s, uint8_t limit, uint16_t number) +{ + s += limit; + *s = 0; + + while (limit--) + { + *--s = (number % 10) + '0'; + number /= 10; + } +} + +#pragma save +#pragma disable_warning 85 +void +set_hw_border(uint8_t c) +{ + __asm; + ld bc, #0x7f10 + out (c), c + ld hl, #2 + add hl, sp + ld c, (hl) + out (c), c + __endasm; +} +#pragma restore + +#pragma save +#pragma disable_warning 85 +void +set_hw_ink(uint8_t ink, uint8_t c) +{ + __asm; + ld hl, #2 + add hl, sp + ld a, (hl) + inc hl + ld e, (hl) + ld bc, #0x7f00 + out (c), a + ld a, #0x40 + or e + out (c), a + __endasm; +} +#pragma restore + +#pragma save +#pragma disable_warning 85 +void +set_hw_mode(uint8_t m) +{ + __asm; + ld hl, #2 + add hl, sp + ld e, (hl) + out (c), a + ld a, #0x8c + or e + ld bc, #0x7f00 + out (c), a + __endasm; +} +#pragma restore + + +void +wait_vsync() +{ + __asm; + ld b, #0xf5 + keep_waiting: + in a, (c) + rra + jr nc, keep_waiting + __endasm; +} + +// this is quite slow, use it only where speed is not an issue +uint16_t +screen_addr(uint16_t x, uint16_t y) +{ + // up to 160 x 200 + return (0xc000 + x + ((y / 8) * 80) + ((y % 8) * 2048)); +} + +void +init_tiles() +{ + uint8_t i, j; + + for (j = 0; j < TMH; j++) + for (i = 0; i < TMW; i++) + { + tiles[i + j * TMW].t = NULL; + tiles[i + j * TMW].saddr = screen_addr((uint16_t)(20 + i * TW / 2), (uint16_t)(8 + j * TH)); + tiles[i + j * TMW].baddr = BUFF_ADDR + (i * TW / 2) + (j * TH * TMW * TW / 2); + tiles[i + j * TMW].n = NULL; + tiles[i + j * TMW].dirty = T_CLEAN; + } + + dirty = NULL; + last_dirty = NULL; +} + +void +update_screen() +{ + // tiles are expected to be 12x9 pixels + __asm; + ld b, #0xf5 + update_keep_waiting: + in a, (c) + rra + jr nc, update_keep_waiting + + ld bc, (_dirty) + + update_loop: + ld a, b + or c + jr z, update_done + + ld hl, #2 + add hl, bc + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + + push bc + ld a, #9 + put_tile0: + ldi + ldi + ldi + ldi + ldi + ldi + + dec a + jp z, put_tile2 + + ld bc, #0x24 + add hl, bc + + ex de, hl + ld bc, #0x07fa + add hl, bc + jp nc, put_tile1 + ld bc, #0xc050 + add hl, bc + put_tile1: + ex de, hl + jr put_tile0 + + put_tile2: + pop bc + + xor a + ld hl, #6 + add hl, bc + ld (hl), a + + inc hl + ld c, (hl) + inc hl + ld b, (hl) + + jp update_loop + + update_done: + __endasm; + + dirty = NULL; + last_dirty = NULL; +} + +void +validate_screen() +{ + for (; dirty; dirty = dirty->n) + dirty->dirty = T_CLEAN; + + dirty = NULL; + last_dirty = NULL; +} + +void +invalidate_screen() +{ + uint8_t i; + + for (i = 0; i < (TMW * TMH) - 1; i++) + { + tiles[i].dirty = T_DIRTY; + tiles[i].n = &tiles[i + 1]; + } + + tiles[i].dirty = T_DIRTY; + tiles[i].n = NULL; + + dirty = tiles; + last_dirty = &tiles[i]; +} + +void +invalidate_tile(struct st_tile *st) +{ + if (st->dirty) + return; + + st->dirty = T_DIRTY; + st->n = NULL; + + if (!dirty) + { + dirty = st; + last_dirty = st; + } + else + { + last_dirty->n = st; + last_dirty = st; + } +} + +inline void +invalidate_tile_xy(uint8_t x, uint8_t y) +{ + // x and y in tilemap coordinates + + invalidate_tile(&tiles[x + y * TMW]); +} + +void +erase_tile(struct st_tile *st) +{ + if (!st || !st->t) + return; + + invalidate_tile(st); + + tile_p = st; + __asm; + ld ix, (_tile_p) + + ld e, 4(ix) + ld d, 5(ix) + ld l, 0(ix) + ld h, 1(ix) + + ld a, #9 + blit_tile0: + ldi + ldi + ldi + ldi + ldi + ldi + + ex de, hl + ld bc, #0x24 + add hl, bc + ex de, hl + + dec a + jp nz, blit_tile0 + __endasm; +} + +inline void +erase_tile_xy(uint8_t x, uint8_t y) +{ + // x and y in tilemap coordinates + erase_tile(&tiles[x + y * TMW]); +} + +void +put_tile(uint8_t *t, uint8_t x, uint8_t y) +{ + // x and y in tilemap coordinates + tile_p = &tiles[x + y * TMW]; + tile_p->t = t; + + erase_tile(tile_p); +} + +// EOF diff --git a/splib.h b/splib.h new file mode 100644 index 0000000..7a063b5 --- /dev/null +++ b/splib.h @@ -0,0 +1,64 @@ +/* + The Return of Traxtor (Amstrad CPC) + Copyright (C) 2015 Juan J. Martinez + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ +#ifndef _SPLIB_H +#define _SPLIB_H + +#include + +// CONFIGURE ** +// this is ; 84x180 pixels tiles +#define TMW 7 +#define TMH 20 + +#define TW 12 +#define TH 9 + +#define BUFF_ADDR 0x0100 +// CONFIGURE ** + +struct st_tile +{ + uint8_t *t; + uint16_t saddr; + uint16_t baddr; + uint8_t dirty; + struct st_tile *n; +}; + +void init_tiles(); +void update_screen(); +void validate_screen(); +void invalidate_screen(); + +void invalidate_tile(struct st_tile *st); +void invalidate_tile_xy(uint8_t x, uint8_t y); + +void erase_tile(struct st_tile *st); +void erase_tile_xy(uint8_t x, uint8_t y); + +void put_tile(uint8_t *t, uint8_t x, uint8_t y); + +// misc +uint16_t screen_addr(uint16_t x, uint16_t y); +void wait_vsync(); +void set_hw_mode(uint8_t m); +void set_hw_border(uint8_t c); +void set_hw_ink(uint8_t ink, uint8_t c); +void pad_numbers(uint8_t *s, uint8_t limit, uint16_t number); + +#endif // _SPLIB_H diff --git a/tiles-work.png b/tiles-work.png new file mode 100644 index 0000000..f6c9953 Binary files /dev/null and b/tiles-work.png differ diff --git a/tiles.png b/tiles.png new file mode 100644 index 0000000..eb7ca34 Binary files /dev/null and b/tiles.png differ diff --git a/tiles_alt.png b/tiles_alt.png new file mode 100644 index 0000000..e4e93f0 Binary files /dev/null and b/tiles_alt.png differ diff --git a/tools/2CDT/2cdt.cbp b/tools/2CDT/2cdt.cbp new file mode 100644 index 0000000..41deaf1 --- /dev/null +++ b/tools/2CDT/2cdt.cbp @@ -0,0 +1,43 @@ + + + + + + \ No newline at end of file diff --git a/tools/2CDT/2cdt.depend b/tools/2CDT/2cdt.depend new file mode 100644 index 0000000..7427b7c --- /dev/null +++ b/tools/2CDT/2cdt.depend @@ -0,0 +1,22 @@ +# depslib dependency file v1.0 +1137940710 source:d:\www\download\2cdt\2cdt\src\tzxfile.c + + + + "tzxfile.h" + +991048958 d:\www\download\2cdt\2cdt\src\tzxfile.h + "defs.h" + +1014464942 d:\www\download\2cdt\2cdt\src\defs.h + +1280219172 source:d:\www\download\2cdt\2cdt\src\2cdt.c + + + + + + "defs.h" + "tzxfile.h" + "getopt.h" + diff --git a/tools/2CDT/2cdt.layout b/tools/2CDT/2cdt.layout new file mode 100644 index 0000000..b5fceb8 --- /dev/null +++ b/tools/2CDT/2cdt.layout @@ -0,0 +1,7 @@ + + + + + + + diff --git a/tools/2CDT/COPYING b/tools/2CDT/COPYING new file mode 100644 index 0000000..196760e --- /dev/null +++ b/tools/2CDT/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/tools/2CDT/Makefile b/tools/2CDT/Makefile new file mode 100644 index 0000000..379c9c6 --- /dev/null +++ b/tools/2CDT/Makefile @@ -0,0 +1,24 @@ +# Makefile for 2cdt utility + +.PHONY: clean +CC = gcc +BIND = gcc +RM = rm + +# CFLAGS flags for C compile +# LFLAGS1 flags after output file spec, before obj file list +# LFLAGS2 flags after obj file list (libraries, etc) + +CFLAGS = -O2 -O3 -DUNIX +LFLAGS1 = +LFLAGS2 = -s + +CDT_O= src/2cdt.o src/tzxfile.o + +2cdt: $(CDT_O) + $(BIND) $(CDT_O) -o 2cdt $(LFLAGS1) $(LFLAGS2) $(LIBS) + +clean: + rm -rf src/*.o + rm -f 2cdt + rm -f 2cdt.exe diff --git a/tools/2CDT/Makefile.win b/tools/2CDT/Makefile.win new file mode 100644 index 0000000..39714b8 --- /dev/null +++ b/tools/2CDT/Makefile.win @@ -0,0 +1,33 @@ +# Project: 2cdt +# Makefile created by Dev-C++ 4.9.9.2 + +CPP = g++.exe +CC = gcc.exe +WINDRES = windres.exe +RES = +OBJ = src/2cdt.o src/tzxfile.o $(RES) +LINKOBJ = src/2cdt.o src/tzxfile.o $(RES) +LIBS = -L"C:/Dev-Cpp/lib" +INCS = -I"C:/Dev-Cpp/include" +CXXINCS = -I"C:/Dev-Cpp/lib/gcc/mingw32/3.4.2/include" -I"C:/Dev-Cpp/include/c++/3.4.2/backward" -I"C:/Dev-Cpp/include/c++/3.4.2/mingw32" -I"C:/Dev-Cpp/include/c++/3.4.2" -I"C:/Dev-Cpp/include" +BIN = 2cdt.exe +CXXFLAGS = $(CXXINCS) +CFLAGS = $(INCS) +RM = rm -f + +.PHONY: all all-before all-after clean clean-custom + +all: all-before 2cdt.exe all-after + + +clean: clean-custom + ${RM} $(OBJ) $(BIN) + +$(BIN): $(OBJ) + $(CC) $(LINKOBJ) -o "2cdt.exe" $(LIBS) + +src/2cdt.o: src/2cdt.c + $(CC) -c src/2cdt.c -o src/2cdt.o $(CFLAGS) + +src/tzxfile.o: src/tzxfile.c + $(CC) -c src/tzxfile.c -o src/tzxfile.o $(CFLAGS) diff --git a/tools/2CDT/file_id.diz b/tools/2CDT/file_id.diz new file mode 100644 index 0000000..e1ff8f5 --- /dev/null +++ b/tools/2CDT/file_id.diz @@ -0,0 +1,16 @@ +2CDT +Copyright (C) Kevin Thacker, 2000-2002 + +23-February-2002 + +2CDT is a tool to create a ".CDT" +tape image from a file in the Amstrad +operating system cassette format. +It can be used to test support +for ".TZX" in Amstrad emulators +and a starting point for a Amstrad +".CDT" tool. + +Source included. + +makefile included for UNIX \ No newline at end of file diff --git a/tools/2CDT/readme.txt b/tools/2CDT/readme.txt new file mode 100644 index 0000000..b10fcc2 --- /dev/null +++ b/tools/2CDT/readme.txt @@ -0,0 +1,135 @@ +2CDT +==== + +(c) Kevin Thacker + +(Original code written in May 2000, fixed and released in May 2001) + +2CDT is a utility to transfer files into a ".CDT" Tape-Image. + +A ".CDT" is a tape-image file which describes the data stored on a cassette tape. + +This file format is very powerful and can describe fast and custom loaders as well +as standard operating system formats. + +The ".CDT" file format is identical to the ".TZX" format. The extension is used +to differentiate between Spectrum and Amstrad Tape-Images. + +The ".TZX" file format was originally designed to store Spectrum tape programs, +it's format can be found from various sources, one of these is "World Of Spectrum": +http://www.void.jump.org/ + +There are a number of tools which already create .TZX files, Taper, Voc2TZX and MakeTZX. +However, these are designed to recognise Spectrum tape loaders, and so do not do well +at creating a tape-image for Amstrad formats. + +This tool has been designed as a starting point for furthur Amstrad CDT tools, +and as a program to generate reference tape-images which can be used by emulator +authors to support this tape-image format in their programs. + +This tool is designed to "inject" one or more file into a ".CDT" in the format written +by the Amstrad operating system. The tool allows the user to define the ".CDT" "recording" +method and baud rate. + +2CDT [parameters] + +parameters: + -n + - Blank CDT file before use + + Use this to create a new CDT, otherwise file + will be added to the end of an existing CDT. + + -s + - Write data with 'speed write' 0 or 1. + + This is the same as typing "SPEED WRITE 0" or "SPEED WRITE 1" + in BASIC. Speed Write '0' is 1000 baud. Speed write '1' is + 2000 baud. + + -b + - Specify Baud Rate. + + Allows you to specify faster or slower loading. + + -t + - Method to write data into TZX (for Amstrad blocks) + 0 = Pure Data Block + 1 = Turbo Loading Data Block (default) + + -m + - Method to write CPC data + 0 = blocks (default) + 1 = headerless (Firmware function CAS READ for reading, CAS WRITE for writing ) + To be loaded with firmware function CAS READ. + Not readable from BASIC. Allows entire program + to be stored as a single continuous block. + 2 = Spectrum ROM loader + + -r + - Give the tape file a name. Up to 16 characters. + + This allows you to give the file on tape a different + name to the name given on your local filesystem. + + If no name is defined, the file will be unnamed. + This option applies to CPC 'blocks' methods only. + + -X
+ Define execution address (where file doesn't have header), or + override execution address (where file has a header) + + -L
+ Define load address (where file doesn't have header), or + override load address (where file has a header) + + -T
+ Define type (where file doesn't have header), or + override type address (where file has a header) + 0 = BASIC, 2 = BINARY + + -p + Set initial pause (default 3000ms) + + -P + Add a small initial pause block for buggy emulators (e.g. old versions of Arnold) + Not recommended. Please use newer version of this emulator. + +Examples: + +The following in a bacth file will create the master tape for 'Stranded': + +REM create new CDT and put binary loader +2cdt -n -r stranded strandlod.bin stranded.cdt +REM add screen to existing CDT data +2cdt -r screen loading.bin stranded.cdt +REM add code to existing CDT data +2cdt -r code stranded.bin stranded.cdt + +If you wanted to create a master tape for a game called 'Columns': + +REM create new CDT and put binary loader +2cdt -n -r loader colload.bin columns.cdt +REM put binary file as headerless +2cdt -m 1 colcode.bin columns.cdt + + + +This archive contains a Windows command-line executable that will run under Win95, Win98, +Win2000 and WinNT. + +License: + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. \ No newline at end of file diff --git a/tools/2CDT/src/2cdt.c b/tools/2CDT/src/2cdt.c new file mode 100644 index 0000000..c3fb520 --- /dev/null +++ b/tools/2CDT/src/2cdt.c @@ -0,0 +1,1290 @@ +/* + * 2CDT Copyright (c) Kevin Thacker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +/* The following program is designed to create a .tzx/.cdt from a tape-file stored +on the PC */ + +#include +#include +#include +#ifdef UNIX +#include +#else +#include +#endif +#include "defs.h" +#include "tzxfile.h" +#include "getopt.h" + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef unsigned __int64 ulong64; +typedef signed __int64 long64; +#else +typedef unsigned long long ulong64; +typedef signed long long long64; +#endif + +enum +{ + CPC_METHOD_BLOCKS = 0, + CPC_METHOD_HEADERLESS, + CPC_METHOD_SPECTRUM, +}; + +static int ExecutionAddress; +static BOOL ExecutionAddressOverride; +static int LoadAddress; +static BOOL LoadAddressOverride; +static int Type; +static BOOL TypeOverride; +static int Pause; +static BOOL BuggyEmuExtraPause; + +#define MAXFILELEN 16 + +static int BaudRate; /* baud rate to write data */ +static int TZXWriteMethod; /* method to write data into TZX file */ +static BOOL BlankBeforeUse; /* blank existing CDT file before use */ +static int CPCMethod = CPC_METHOD_BLOCKS; + +/* I am using a enum, so that I can poke data into structures without +worrying how the compiler has aligned it */ +enum +{ + CPC_TAPE_HEADER_FILENAME_BYTE0 = 0, + CPC_TAPE_HEADER_FILENAME_BYTE1, + CPC_TAPE_HEADER_FILENAME_BYTE2, + CPC_TAPE_HEADER_FILENAME_BYTE3, + CPC_TAPE_HEADER_FILENAME_BYTE4, + CPC_TAPE_HEADER_FILENAME_BYTE5, + CPC_TAPE_HEADER_FILENAME_BYTE6, + CPC_TAPE_HEADER_FILENAME_BYTE7, + CPC_TAPE_HEADER_FILENAME_BYTE8, + CPC_TAPE_HEADER_FILENAME_BYTE9, + CPC_TAPE_HEADER_FILENAME_BYTE10, + CPC_TAPE_HEADER_FILENAME_BYTE11, + CPC_TAPE_HEADER_FILENAME_BYTE12, + CPC_TAPE_HEADER_FILENAME_BYTE13, + CPC_TAPE_HEADER_FILENAME_BYTE14, + CPC_TAPE_HEADER_FILENAME_BYTE15, + CPC_TAPE_HEADER_BLOCK_NUMBER, + CPC_TAPE_HEADER_LAST_BLOCK_FLAG, + CPC_TAPE_HEADER_FILE_TYPE, + CPC_TAPE_HEADER_DATA_LENGTH_LOW, + CPC_TAPE_HEADER_DATA_LENGTH_HIGH, + CPC_TAPE_HEADER_DATA_LOCATION_LOW, + CPC_TAPE_HEADER_DATA_LOCATION_HIGH, + CPC_TAPE_HEADER_FIRST_BLOCK_FLAG, + CPC_TAPE_HEADER_DATA_LOGICAL_LENGTH_LOW, + CPC_TAPE_HEADER_DATA_LOGICAL_LENGTH_HIGH, + CPC_TAPE_HEADER_DATA_EXECUTION_ADDRESS_LOW, + CPC_TAPE_HEADER_DATA_EXECUTION_ADDRESS_HIGH, +} CPC_TAPE_HEADER_ENUM; + +/* size of header */ +#define CPC_TAPE_HEADER_SIZE 64 + +/* load a file into memory */ +BOOL Host_LoadFile(const char *Filename, unsigned char **pLocation, unsigned long *pLength) +{ + FILE *fh; + unsigned char *pData; + + *pLocation = NULL; + *pLength = 0; + + if (Filename!=NULL) + { + if (strlen(Filename)!=0) + { + fh = fopen(Filename,"rb"); + + if (fh!=NULL) + { + int FileSize; + +#ifdef WIN32 + int FNo; + + FNo = _fileno(fh); + FileSize = _filelength(FNo); +#else + unsigned long CurrentPosition; + CurrentPosition = ftell(fh); + fseek(fh, 0, SEEK_END); + FileSize = ftell(fh); + fseek(fh, CurrentPosition, SEEK_SET); +#endif + if (FileSize!=0) + { + pData = (unsigned char *)malloc(FileSize); + + if (pData!=NULL) + { + if (fread(pData,1,FileSize,fh)==FileSize) + { + *pLocation = pData; + *pLength = FileSize; + fclose(fh); + return TRUE; + } + + free(pData); + } + } + + fclose(fh); + } + } + } + + return FALSE; +} + + +/* calculate checksum as AMSDOS would for the first 66 bytes of a datablock */ +/* this is used to determine if a file has a AMSDOS header */ +unsigned int AMSDOS_CalculateChecksum(unsigned char *pHeader) +{ + unsigned int Checksum; + int i; + + Checksum = 0; + + for (i=0; i<67; i++) + { + unsigned int CheckSumByte; + + CheckSumByte = pHeader[i] & 0x0ff; + + Checksum+=CheckSumByte; + } + + return Checksum; +} + +/* CRC code shamelessly taken from Pierre Guerrier's AIFF decoder! */ +#define kCRCpoly 4129 /* used for binary long division in CRC */ + +/* CRC polynomial: X^16+X^12+X^5+1 */ +unsigned int CRCupdate(unsigned int CRC, unsigned char new) +{ + unsigned int aux = CRC ^ (new << 8); + int i; + + for(i=0; i<8; i++) + if (aux & 0x8000) + aux = (aux <<= 1) ^ kCRCpoly; + else + aux <<= 1; + + return(aux); +} + +/* +ID : 11 - Turbo loading data block +------- + This block is very similar to the normal TAP block but with some + additional info on the timings and other important differences. + The same tape encoding is used as for the standard speed data block. + If a block should use some non-standard sync or pilot tones (for + example all sorts of protection schemes) then use the next three blocks + to describe it. + +00 2 Length of PILOT pulse [2168] +02 2 Length of SYNC First pulse [667] +04 2 Length of SYNC Second pulse [735] +06 2 Length of ZERO bit pulse [855] +08 2 Length of ONE bit pulse [1710] +0A 2 Length of PILOT tone (in PILOT pulses) [8064 Header, 3220 Data] +0C 1 Used bits in last byte (other bits should be 0) [8] + i.e. if this is 6 then the bits (x) used in last byte are: xxxxxx00 +0D 2 Pause After this block in milliseconds (ms) [1000] +0F 3 Length of following data +12 x Data; format is as for TAP (MSb first) + +- Length: [0F,10,11]+12 +*/ + +/* 2 pulses per bit, tone is composed of 1 bits */ +#define CPC_PILOT_TONE_NUM_WAVES (2048) +#define CPC_PILOT_TONE_NUM_PULSES (CPC_PILOT_TONE_NUM_WAVES*2) + +#define CPC_NOPS_PER_FRAME (19968) +#define CPC_NOPS_PER_SECOND (CPC_NOPS_PER_FRAME*50) +#define CPC_T_STATES (CPC_NOPS_PER_SECOND*4) + +#define T_STATE_CONVERSION_FACTOR (TZX_T_STATES<<8)/(CPC_T_STATES>>8) +/* pause between each block */ +#define CPC_PAUSE_AFTER_BLOCK_IN_MS 2500 +/* pause between tape header and data for block */ +#define CPC_PAUSE_AFTER_HEADER_IN_MS 14 + +void InitialiseStandardSpeedDataBlock(TZX_BLOCK *pBlock, int Pause) +{ + unsigned char *pHeader = TZX_GetBlockHeaderPtr(pBlock); + + if (pHeader!=NULL) + { + /* check it is a turbo-loading data block */ + if (pHeader[0] == TZX_STANDARD_SPEED_DATA_BLOCK) + { + pHeader++; + + pHeader[0x00] = (Pause & 0x0ff); + pHeader[0x01] = (Pause>>8); + + + } + } +} + +void CPC_InitialiseTurboLoadingDataBlock(TZX_BLOCK *pBlock, int BaudRate,int Pause) +{ + unsigned char *pHeader = TZX_GetBlockHeaderPtr(pBlock); + + if (pHeader!=NULL) + { + /* check it is a turbo-loading data block */ + if (pHeader[0] == TZX_TURBO_LOADING_DATA_BLOCK) + { + int ZeroPulseLengthInMicroseconds; + long64 ZeroPulseLengthInCPCTStates; + int OnePulseLength; + int ZeroPulseLength; + + pHeader++; + /* equation from CPC firmware guide: + Average baud rate: = 1 000 000/(3*half zero length) = 333 333/Half zero length + */ + + ZeroPulseLengthInMicroseconds = 333333/BaudRate; + ZeroPulseLengthInCPCTStates = ZeroPulseLengthInMicroseconds<<2; + + ZeroPulseLength = (ZeroPulseLengthInCPCTStates* + (T_STATE_CONVERSION_FACTOR>>8))>>8; + + /* one pulse is twice the size of a zero pulse */ + OnePulseLength = ZeroPulseLength<<1; + + /* PILOT pulse on CPC is a one bit */ + pHeader[0x00] = (unsigned char)OnePulseLength; + pHeader[0x01] = (unsigned char)(OnePulseLength>>8); + + /* SYNC on CPC is a zero bit, both sync pulses will be the same */ + pHeader[0x02] = pHeader[0x04] = (unsigned char)ZeroPulseLength; + pHeader[0x03] = pHeader[0x05] = (unsigned char)(ZeroPulseLength>>8); + + /* write zero pulse length */ + pHeader[0x06] = (unsigned char)ZeroPulseLength; + pHeader[0x07] = (unsigned char)(ZeroPulseLength>>8); + + /* write one pulse length */ + pHeader[0x08] = (unsigned char)OnePulseLength; + pHeader[0x09] = (unsigned char)(OnePulseLength>>8); + + /* PILOT pulse is same as 1 Pulse */ + /* pilot tone is 2048 bits long */ + pHeader[0x0a] = CPC_PILOT_TONE_NUM_PULSES & 0x0ff; + pHeader[0x0b] = (CPC_PILOT_TONE_NUM_PULSES>>8); + + /* the end of the block will be the trailer bytes. Say all bits are + used, although, because it doesn't contain useful data it doesn't matter */ + pHeader[0x0c] = 8; + + pHeader[0x0d] = (Pause & 0x0ff); + pHeader[0x0e] = (Pause>>8); + + + } + } +} + + + +void WriteStandardSpeedDataBlock(TZX_FILE *pFile, unsigned char SyncPattern, unsigned char *pData, int DataSize, int Pause) +{ + TZX_BLOCK *pBlock; + unsigned char *pBlockData; + + pBlock = TZX_CreateBlock(TZX_STANDARD_SPEED_DATA_BLOCK); + InitialiseStandardSpeedDataBlock(pBlock, Pause); + + if (pBlock!=NULL) + { + /* one byte for sync, one byte for checksum */ + int TZX_DataBlockSize = DataSize+2; + + /* add block to end of file */ + TZX_AddBlockToEndOfFile(pFile,pBlock); + + /* allocate data in block */ + TZX_AddDataToBlock(pBlock, TZX_DataBlockSize); + + pBlockData= TZX_GetBlockDataPtr(pBlock); + + if (pBlockData!=NULL) + { + char CheckSum = SyncPattern; + int i; + + /* write pattern */ + *pBlockData = SyncPattern; + ++pBlockData; + + for (i=0; i>8; + + /* each tape block is split into 256 chunks, each chunk has a CRC */ + + /* size of all chunks, plus CRC's for each block */ + TZX_DataBlockSize = + /* size of all chunks */ + (NumChunks<<8) + + /* size of CRC's for all chunks */ + (NumChunks<<1) + + /* size of trailer in bytes */ + 4 + + /* size of sync pattern */ + 1; + + + + pBlock = TZX_CreateBlock(TZX_TURBO_LOADING_DATA_BLOCK); + CPC_InitialiseTurboLoadingDataBlock(pBlock, BaudRate,Pause); + + + if (pBlock!=NULL) + { + /* add block to end of file */ + TZX_AddBlockToEndOfFile(pFile,pBlock); + + /* allocate data in block */ + TZX_AddDataToBlock(pBlock, TZX_DataBlockSize); + + pBlockData= TZX_GetBlockDataPtr(pBlock); + + if (pBlockData!=NULL) + { + int i,j; + unsigned char *pDataPtr; + int DataSizeRemaining; + unsigned char *pBlockPtr; + unsigned short CRC; + + pDataPtr = pData; + DataSizeRemaining = DataSize; + pBlockPtr = pBlockData; + + /* write pattern */ + pBlockPtr[0] = SyncPattern; + pBlockPtr++; + + /* write each chunk in turn and calculate CRC */ + for (i=0; i>8)^0x0ff; + pBlockPtr++; + pBlockPtr[0] = CRC^0x0ff; + pBlockPtr++; + } + + + /* write trailer */ + memset(pBlockPtr, 0x0ff, 4); + } + } +} + +/* +ID : 14 - Pure data block +------- + This is the same as in the turbo loading data block, except that it has + no pilot or sync pulses. + +00 2 Length of ZERO bit pulse +02 2 Length of ONE bit pulse +04 1 Used bits in LAST Byte +05 2 Pause after this block in milliseconds (ms) +07 3 Length of following data +0A x Data +*/ + +void CPC_InitialisePureDataBlock(TZX_BLOCK *pBlock, int BaudRate, int Pause) +{ + unsigned char *pHeader = TZX_GetBlockHeaderPtr(pBlock); + + if (pHeader!=NULL) + { + /* check it is a turbo-loading data block */ + if (pHeader[0] == TZX_PURE_DATA_BLOCK) + { + int ZeroPulseLengthInMicroseconds; + long64 ZeroPulseLengthInCPCTStates; + int OnePulseLength; + int ZeroPulseLength; + + pHeader++; + /* equation from CPC firmware guide: + Average baud rate: = 1 000 000/(3*half zero length) = 333 333/Half zero length + */ + + ZeroPulseLengthInMicroseconds = 333333/BaudRate; + ZeroPulseLengthInCPCTStates = ZeroPulseLengthInMicroseconds<<2; + + ZeroPulseLength = (ZeroPulseLengthInCPCTStates* + (T_STATE_CONVERSION_FACTOR>>8))>>8; + + /* one pulse is twice the size of a zero pulse */ + OnePulseLength = ZeroPulseLength<<1; + /* write zero pulse length */ + pHeader[0x00] = ZeroPulseLength; + pHeader[0x01] = ZeroPulseLength>>8; + + /* write one pulse length */ + pHeader[0x02] = OnePulseLength; + pHeader[0x03] = OnePulseLength>>8; + + /* the end of the block will be the trailer bytes. Say all bits are + used, although, because it doesn't contain useful data it doesn't matter */ + pHeader[0x04] = 8; + + /* write pause */ + pHeader[0x05] = (Pause & 0x0ff); + pHeader[0x06] = (Pause>>8) & 0x0ff; + + + } + } +} + + +/* the following is for a bitstream */ +unsigned char *pData; +unsigned long ByteCount; +unsigned long BitCount; + +/* initialise bit stream with buffer to write data to */ +void BitStream_Initialise(unsigned char *pBuffer) +{ + pData = pBuffer; + ByteCount = 0; + BitCount = 0; +} + +/* write bit to stream */ +void BitStream_WriteBit(int Bit) +{ + unsigned char Data; + + /* get current data written */ + Data = pData[ByteCount]; + Data &= ~(1<<(7-BitCount)); + Data |= (Bit<<(7-BitCount)); + pData[ByteCount] = Data; + + /* increment bit count */ + BitCount++; + /* if we overrun 8-bits, then bit 3 will be set, add this on */ + ByteCount += (BitCount>>3); + /* mask off bit count */ + BitCount &= 0x07; +} + +/* write byte to stream */ +void BitStream_WriteByte(unsigned char Byte) +{ + int b; + int Bit; + unsigned char LocalByte; + + LocalByte = Byte; + + for (b=0; b<8; b++) + { + Bit = LocalByte & 0x080; + Bit = Bit>>7; + BitStream_WriteBit(Bit); + LocalByte = LocalByte<<1; + } +} + + + +/* write a block of data to a file */ +void CPC_WritePureDataBlock(TZX_FILE *pFile, unsigned char SyncPattern, unsigned char *pData, int DataSize, int Pause) +{ + TZX_BLOCK *pBlock; + unsigned char *pBlockData; + + int NumChunks; + int TZX_DataBlockSize; + + /* divide into complete 256 byte blocks */ + NumChunks = (DataSize+255)>>8; + + /* each tape block is split into 256 chunks, each chunk has a CRC */ + + /* size of all chunks, plus CRC's for each block */ + TZX_DataBlockSize = + /* size of all chunks */ + (NumChunks<<8) + + /* size of CRC's for all chunks */ + (NumChunks<<1) + + /* size of trailer in bytes */ + 4 + + /* size of sync pattern */ + 1; + + TZX_DataBlockSize+= + /* pilot tone - CPC_PILOT_TONE_NUM_WAVES 1 bit's, a zero bit then data as before ... */ + ((CPC_PILOT_TONE_NUM_WAVES + 1)+7)>>3; + + pBlock = TZX_CreateBlock(TZX_PURE_DATA_BLOCK); + CPC_InitialisePureDataBlock(pBlock, BaudRate,Pause); + + + if (pBlock!=NULL) + { + /* add block to end of file */ + TZX_AddBlockToEndOfFile(pFile,pBlock); + + /* allocate data in block */ + TZX_AddDataToBlock(pBlock, TZX_DataBlockSize); + + pBlockData= TZX_GetBlockDataPtr(pBlock); + + if (pBlockData!=NULL) + { + int i,j; + unsigned char *pDataPtr; + int DataSizeRemaining; + unsigned char *pBlockPtr; + unsigned short CRC; + + pDataPtr = pData; + DataSizeRemaining = DataSize; + pBlockPtr = pBlockData; + + BitStream_Initialise(pBlockPtr); + + /* write leader */ + for (i=0; i>8)); + BitStream_WriteByte(CRC); + } + + /* write trailer */ + for (i=0; i<32; i++) + { + BitStream_WriteBit(1); + } + } + } +} + +/* write a data block in format specified */ +void CPC_WriteDataBlock(TZX_FILE *pFile, unsigned char SyncByte, unsigned char *pData, unsigned long DataSize, int Pause) +{ + switch (TZXWriteMethod) + { + case TZX_TURBO_LOADING_DATA_BLOCK: + { + CPC_WriteTurboLoadingDataBlock(pFile, SyncByte, pData, DataSize,Pause); + } + break; + + case TZX_PURE_DATA_BLOCK: + { + /* write header */ + CPC_WritePureDataBlock(pFile, SyncByte, pData, DataSize,Pause); + } + break; + } +} + +#define UTILITY_NAME "2CDT" + +void DisplayInfo() +{ + printf("%s will transfer files into a .CDT/.TZX tape image, in Amstrad CPC/CPC+\r\n", UTILITY_NAME); + printf("KC Compact form.\r\n\r\n"); + printf("Usage: %s [arguments] <.cdt image>\r\n\r\n", UTILITY_NAME); + printf("-n - Blank CDT file before use\n"); + printf("-b - Specify Baud rate (default 2000)\n"); + printf("-s <0 or 1> - Specify 'Speed Write'.\n"); + printf(" 0 = 1000 baud, 1 = 2000 baud (default)\n"); + printf("-t - TZX Block Write Method.\n"); + printf(" 0 = Pure Data, 1 = Turbo Loading (default)\n"); + printf("-m - Data method\n"); + printf(" 0 = blocks (default)\n"); + printf(" 1 = headerless (Firmware function: CAS READ - &BCA1) \n"); + printf(" 2 = spectrum \n"); + printf(" 3 = Two blocks. First block of 2K, second block has remainder\n"); + printf(" 4 = Two blocks. First block of 1 byte, second block has remainder\n"); + printf("-X = Define or override execution address (default is &1000 if no header)\r\n"); + printf("-L = Define or override load address (default is &1000 if no header)\r\n"); + printf("-F = Define or override file type (0=BASIC, 2=Binary (default if no header)) etc. Applies to Data method 0\r\n"); + printf("-p = Set initial pause in milliseconds (default 3000ms)\r\n"); + printf("-P = Add a 1ms pause for buggy emulators that ignore first block\r\n"); + printf("-r \n"); + printf(" - Add as to CDT (rename file)\n"); +} + +extern char *optarg; + +int ReadNumberParameter(char *param) +{ + int Length = strlen(param); + BOOL bIsHex = FALSE; + int Offset = 0; + unsigned long Value = 0; + char ch; + + if (Length==0) + return 0; + + /* check for common prefixs for hex numbers */ + if ((Length>1) && ((param[0]=='&') || (param[0]=='$'))) + { + Offset = 1; + bIsHex = TRUE; + } + else if ((Length>2) && (param[0]=='0') && ((param[1]=='x') || (param[1]=='X'))) + { + Offset = 2; + bIsHex = TRUE; + } + + if (!bIsHex) + { + return atoi(param); + } + + ch = param[Offset]; + while (ch!='\0') + { + Value = Value<<4; + if ((ch>='0') && (ch<='9')) + { + Value = Value | (ch-'0'); + } + else if ((ch>='a') && (ch<='f')) + { + Value = Value | ((ch-'a')+10); + } + else if ((ch>='A') && (ch<='F')) + { + Value = Value | ((ch-'A')+10); + } + Offset++; + ch = param[Offset]; + } + + return Value; +} + +int main(int argc, char *argv[]) +{ + unsigned char *pTapeFilename = NULL; + + if (argc==1) + { + DisplayInfo(); + } + else + { + TZX_FILE *pTZXFile; + unsigned char *pSourceFilename; + unsigned char *pDestFilename; + unsigned char *pData; + unsigned long DataLength; + char c; + + /* initialise defaults */ + BaudRate = 2000; + Pause = 3000; + Type = 2; + TypeOverride = FALSE; + LoadAddressOverride = FALSE; + TZXWriteMethod = TZX_TURBO_LOADING_DATA_BLOCK; + BlankBeforeUse = FALSE; + ExecutionAddress = LoadAddress = 0x01000; + ExecutionAddressOverride = FALSE; + LoadAddressOverride = FALSE; + + printf("-n - Blank CDT file before use\n"); + printf("-b - Specify Baud rate (default 2000)\n"); + printf("-s <0 or 1> - Specify 'Speed Write'.\n"); + printf(" 0 = 1000 baud, 1 = 2000 baud (default)\n"); + printf("-t - TZX Block Write Method.\n"); + printf(" 0 = Pure Data, 1 = Turbo Loading (default)\n"); + printf("-m - Data method\n"); + printf(" 0 = blocks (default)\n"); + printf(" 1 = headerless (Firmware function: CAS READ - &BCA1) \n"); + printf(" 2 = spectrum \n"); + printf(" 3 = Two blocks. First block of 2K, second block has remainder\n"); + printf(" 4 = Two blocks. First block of 1 byte, second block has remainder\n"); + printf("-X = Define or override execution address (default is &1000 if no header)\r\n"); + printf("-L = Define or override load address (default is &1000 if no header)\r\n"); + printf("-F = Define or override file type (0=BASIC, 2=Binary (default if no header)) etc. Applies to Data method 0\r\n"); + printf("-p = Set initial pause in milliseconds (default 3000ms)\r\n"); + printf("-P = Add a 1ms pause for buggy emulators that ignore first block\r\n"); + printf("-r \n"); + printf(" - Add as to CDT (rename file)\n"); + + + do + { + c = getopt(argc, argv,"r:nb:p:m:t:F:L:s:X:p:P"); + + switch (c) + { + case 'm': + { + int nMethod = atoi(optarg); + CPCMethod = nMethod; + + } + break; + + case 'p': + { + Pause = atoi(optarg); + if (Pause<0) + { + Pause = 0; + } + } + break; + + case 'r': + { + pTapeFilename = optarg; + } + break; + + case 'n': + { + BlankBeforeUse = TRUE; + } + break; + + case 'b': + { + int Baud = atoi(optarg); + if ((Baud>0) && (Baud<6000)) + BaudRate = Baud; + } + break; + + case 'X': + { + ExecutionAddress = ReadNumberParameter(optarg) & 0x0ffff; + ExecutionAddressOverride = TRUE; + } + break; + + case 'L': + { + LoadAddress = ReadNumberParameter(optarg) & 0x0ffff; + LoadAddressOverride = TRUE; + } + break; + + case 's': + { + int SpeedWrite = atoi(optarg); + if (SpeedWrite==1) + { + BaudRate = 2000; + } + else + { + BaudRate = 1000; + } + } + break; + + case 'F': + { + Type = atoi(optarg) & 0x0ff; + TypeOverride = TRUE; + + + } + break; + + + case 'P': + { + BuggyEmuExtraPause = TRUE; + + } + break; + + case 't': + { + int nMethod = atoi(optarg); + if (nMethod==0) + { + TZXWriteMethod = TZX_PURE_DATA_BLOCK; + } + else if (nMethod==1) + { + TZXWriteMethod = TZX_TURBO_LOADING_DATA_BLOCK; + } + else if (nMethod==2) + { + TZXWriteMethod = TZX_STANDARD_SPEED_DATA_BLOCK; + } + } + break; + + default: + { + } + break; + } + + } + while (c!=-1); + + if ((argc-optind)==0) + { + printf("No source file or destination file have been specified!\n"); + exit(1); + } + + if ((argc-optind)==1) + { + printf("No destination file has been specified\n"); + exit(1); + } + + pSourceFilename = argv[optind]; + pDestFilename = argv[optind+1]; + + /* create TZX file */ + pTZXFile = TZX_CreateFile(TZX_VERSION_MAJOR,TZX_VERSION_MINOR); + + if (pTZXFile!=NULL) + { + int nFile; + + + if (BlankBeforeUse) + { + TZX_BLOCK *pBlock; + + /* if buggy emu, add an extra small pause */ + if (BuggyEmuExtraPause) + { + pBlock = TZX_CreateBlock(TZX_PAUSE_BLOCK); + + if (pBlock!=NULL) + { + /* add a 1ms initial pause for buggy emus */ + TZX_SetupPauseBlock(pBlock, 1); + TZX_AddBlockToEndOfFile(pTZXFile,pBlock); + } + } + + + /* correct pause */ + pBlock = TZX_CreateBlock(TZX_PAUSE_BLOCK); + + if (pBlock!=NULL) + { + TZX_SetupPauseBlock(pBlock, Pause); + TZX_AddBlockToEndOfFile(pTZXFile,pBlock); + } + } + + + if (Host_LoadFile(pSourceFilename, &pData, &DataLength)) + { + int FileOffset; + int FileLengthRemaining; + int TapeBlockSize; + BOOL FirstBlock,LastBlock; + int BlockIndex; + unsigned short BlockLocation; + + /* header for tape file */ + unsigned char TapeHeader[CPC_TAPE_HEADER_SIZE]; + + /* calculate checksum from loaded file */ + unsigned short CalculatedChecksum = (unsigned short)AMSDOS_CalculateChecksum(pData); + + /* get stored checksum */ + unsigned short StoredChecksum = + (pData[67] & 0x0ff) | + (pData[68] & 0x0ff)<<8; + + FileOffset = 0; + FileLengthRemaining = DataLength; + BlockIndex = 1; + FirstBlock =TRUE; + + /* insert a pause block - 1 second, this is added onto the end of the previous block */ + /* if (BlankBeforeUse == FALSE) + { + TZX_BLOCK *pBlock; + + pBlock = TZX_CreateBlock(TZX_PAUSE_BLOCK); + + if (pBlock!=NULL) + { + TZX_SetupPauseBlock(pBlock, 2000); + TZX_AddBlockToEndOfFile(pTZXFile,pBlock); + } + } +*/ + + + /* clear tape header */ + memset(TapeHeader, 0, CPC_TAPE_HEADER_SIZE); + + /* checksum's match? */ + if (CalculatedChecksum==StoredChecksum) + { + /* copy file type */ + TapeHeader[CPC_TAPE_HEADER_FILE_TYPE] = pData[CPC_TAPE_HEADER_FILE_TYPE]; + /* copy execution address */ + TapeHeader[CPC_TAPE_HEADER_DATA_EXECUTION_ADDRESS_LOW] = pData[CPC_TAPE_HEADER_DATA_EXECUTION_ADDRESS_LOW]; + TapeHeader[CPC_TAPE_HEADER_DATA_EXECUTION_ADDRESS_HIGH] = pData[CPC_TAPE_HEADER_DATA_EXECUTION_ADDRESS_HIGH]; + /* copy data location */ + TapeHeader[CPC_TAPE_HEADER_DATA_LOCATION_LOW] = pData[CPC_TAPE_HEADER_DATA_LOCATION_LOW]; + TapeHeader[CPC_TAPE_HEADER_DATA_LOCATION_HIGH] = pData[CPC_TAPE_HEADER_DATA_LOCATION_HIGH]; + + FileOffset+=128; + FileLengthRemaining-=128; + + /* override execution address? */ + if (ExecutionAddressOverride) + { + TapeHeader[CPC_TAPE_HEADER_DATA_EXECUTION_ADDRESS_LOW] = ExecutionAddress&0xFF; + TapeHeader[CPC_TAPE_HEADER_DATA_EXECUTION_ADDRESS_HIGH] = (ExecutionAddress>>8)&0xFF; + } + + /* override type? */ + if (TypeOverride) + { + TapeHeader[CPC_TAPE_HEADER_FILE_TYPE] = Type; + } + + /* override load address? */ + if (LoadAddressOverride) + { + TapeHeader[CPC_TAPE_HEADER_DATA_LOCATION_LOW] = LoadAddress&0xFF; + TapeHeader[CPC_TAPE_HEADER_DATA_LOCATION_HIGH] = (LoadAddress>>8)&0xFF; + } + + } + else + { + /* set type */ + TapeHeader[CPC_TAPE_HEADER_FILE_TYPE] = Type; + + /* set execution address */ + TapeHeader[CPC_TAPE_HEADER_DATA_EXECUTION_ADDRESS_LOW] = ExecutionAddress&0xFF; + TapeHeader[CPC_TAPE_HEADER_DATA_EXECUTION_ADDRESS_HIGH] = (ExecutionAddress>>8)&0xFF; + + /* set load address */ + TapeHeader[CPC_TAPE_HEADER_DATA_LOCATION_LOW] = LoadAddress&0xFF; + TapeHeader[CPC_TAPE_HEADER_DATA_LOCATION_HIGH] = (LoadAddress>>8)&0xFF; + } + + if (pTapeFilename!=NULL) + { + int i; + int nLength = strlen(pTapeFilename); + if (nLength>16) + nLength = 16; + for (i=0; i>8) & 0x0ff; + + + BlockLocation = TapeHeader[CPC_TAPE_HEADER_DATA_LOCATION_LOW] | + (TapeHeader[CPC_TAPE_HEADER_DATA_LOCATION_HIGH]<<8); + + if (CPCMethod == CPC_METHOD_SPECTRUM) + { + /* write data into block */ + WriteStandardSpeedDataBlock(pTZXFile, 0x0ff, &pData[FileOffset], FileLengthRemaining, 1000); + } + else + { + do + { + unsigned char Flag; + /* + CPC can't handle this one + if (CPCMethod == CPC_METHOD_2BLOCKS) + { + if (FirstBlock) + { + TapeBlockSize=CPC_DATA_BLOCK_SIZE; + LastBlock = FALSE; + } + else + { + TapeBlockSize = FileLengthRemaining; + LastBlock = TRUE; + } + } + else + */ + if (CPCMethod == CPC_METHOD_BLOCKS) + { + /* calc size of tape data block */ + if (FileLengthRemaining>CPC_DATA_BLOCK_SIZE) + { + TapeBlockSize = CPC_DATA_BLOCK_SIZE; + LastBlock = FALSE; + } + else + { + TapeBlockSize = FileLengthRemaining; + LastBlock = TRUE; + } + } + else + if (CPCMethod == CPC_METHOD_HEADERLESS) + { + TapeBlockSize = FileLengthRemaining; + } + + + + /**** HEADER ****/ + /* SETUP TAPE RELATED DATA */ + /* block index */ + TapeHeader[CPC_TAPE_HEADER_BLOCK_NUMBER] = BlockIndex; + + /* first block? */ + if (FirstBlock) + { + FirstBlock = FALSE; + + Flag = 0x0ff; + } + else + { + Flag = 0; + } + + TapeHeader[CPC_TAPE_HEADER_FIRST_BLOCK_FLAG] = Flag; + + /* last block? */ + if (LastBlock) + { + Flag = 0x0ff; + } + else + { + Flag = 0; + } + + TapeHeader[CPC_TAPE_HEADER_LAST_BLOCK_FLAG] = Flag; + + /* size of data following */ + TapeHeader[CPC_TAPE_HEADER_DATA_LENGTH_LOW] = (unsigned char)TapeBlockSize; + TapeHeader[CPC_TAPE_HEADER_DATA_LENGTH_HIGH] = (unsigned char)(TapeBlockSize>>8); + + /* location of block */ + TapeHeader[CPC_TAPE_HEADER_DATA_LOCATION_LOW] = (unsigned char)BlockLocation; + TapeHeader[CPC_TAPE_HEADER_DATA_LOCATION_HIGH] = (unsigned char)(BlockLocation>>8); + + /* don't write a header if headerless */ + if (CPCMethod!=CPC_METHOD_HEADERLESS) + { + /* write header */ + CPC_WriteDataBlock(pTZXFile, 0x02c, TapeHeader, CPC_TAPE_HEADER_SIZE,10); + } + + /* write data into block */ + CPC_WriteDataBlock(pTZXFile, 0x016, &pData[FileOffset], TapeBlockSize,CPC_PAUSE_AFTER_BLOCK_IN_MS); + + BlockLocation+=TapeBlockSize; + BlockIndex++; + FileOffset+=TapeBlockSize; + FileLengthRemaining -= TapeBlockSize; + } + while (FileLengthRemaining!=0); + } + + free(pData); + } + + /* write file */ + if (BlankBeforeUse) + { + TZX_WriteFile(pTZXFile, pDestFilename); + } + else + { + TZX_AppendFile(pTZXFile, pDestFilename); + } + + /* free it */ + TZX_FreeFile(pTZXFile); + } + else + { + printf("Failed to open output file!\r\n"); + exit(1); + } + + } + + exit(0); + + return 0; +} diff --git a/tools/2CDT/src/defs.h b/tools/2CDT/src/defs.h new file mode 100644 index 0000000..f042dde --- /dev/null +++ b/tools/2CDT/src/defs.h @@ -0,0 +1,36 @@ +/* + * 2CDT Copyright (c) Kevin Thacker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __DEFS_HEADER_INCLUDED__ +#define __DEFS_HEADER_INCLUDED__ + + +typedef int BOOL; + +#ifndef TRUE +#define TRUE (1==1) +#endif + +#ifndef FALSE +#define FALSE (1==0) +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#endif diff --git a/tools/2CDT/src/tzxfile.c b/tools/2CDT/src/tzxfile.c new file mode 100644 index 0000000..3f550b0 --- /dev/null +++ b/tools/2CDT/src/tzxfile.c @@ -0,0 +1,445 @@ +/* + * 2CDT Copyright (c) Kevin Thacker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +/* TZX file support */ +#include "tzxfile.h" +/* header for TZX file */ +const unsigned char *TZX_FileHeader = (const unsigned char *)"ZXTape!\x1a"; + +/* the internal format for the TZX is a link-list system. +Blocks can be edited. A new file can be written with the new data */ + + + +/**************************************/ +/* insert block after block specified */ +void TZX_InsertBlockAfter(TZX_FILE *pFile,TZX_BLOCK *pBlock, TZX_BLOCK *pPrev) +{ + /* setup block pointers */ + pBlock->pPrev = pPrev; + pBlock->pNext = pPrev->pNext; + + /* setup pointers for block before */ + pPrev->pNext = pBlock; +} + +/***************************************/ +/* insert block before block specified */ +void TZX_InsertBlockBefore(TZX_FILE *pFile, TZX_BLOCK *pBlock, TZX_BLOCK *pNext) +{ + /* setup block pointers */ + pBlock->pNext = pNext; + pBlock->pPrev = pNext->pPrev; + + /* setup pointers for block before */ + pNext->pPrev = pBlock; + + /* is block we are inserting after the first in the list? */ + if (pFile->pFirstBlock == pNext) + { + /* yes. New block is now the start of the list */ + pFile->pFirstBlock = pBlock; + } +} + + +/*****************************************/ +/* insert a block at the end of the file */ +void TZX_AddBlockToEndOfFile(TZX_FILE *pFile, TZX_BLOCK *pBlock) +{ + /* blocks in file? */ + if (pFile->pFirstBlock==NULL) + { + /* no */ + pFile->pFirstBlock = pBlock; + } + else + { + /* yes */ + TZX_BLOCK *pCurrentBlock; + + /* search for last block in list */ + pCurrentBlock = pFile->pFirstBlock; + + while (pCurrentBlock->pNext!=NULL) + pCurrentBlock = pCurrentBlock->pNext; + + TZX_InsertBlockAfter(pFile,pBlock, pCurrentBlock); + } +} + +/********************************/ +/* detach block from block list */ +void TZX_DetachBlock(TZX_FILE *pFile,TZX_BLOCK *pBlock) +{ + /* block before this block? */ + if (pBlock->pPrev!=NULL) + { + /* yes */ + pBlock->pPrev->pNext = pBlock->pNext; + } + else + { + /* no, this block is first in list */ + pFile->pFirstBlock = pBlock->pNext; + } + + /* block after this block? */ + if (pBlock->pNext!=NULL) + { + /* yes */ + pBlock->pNext->pPrev = pBlock->pPrev; + } +} + +/************************/ +/* free data in a block */ +void TZX_FreeBlock(TZX_BLOCK *pBlock) +{ + /* free it */ + free(pBlock); +} + + + +/******************************/ +/* create a internal TZX file */ + +TZX_FILE *TZX_CreateFile(unsigned char VersionMajor, unsigned char VersionMinor) +{ + TZX_FILE *pTZXFile; + + /* alloc the header */ + pTZXFile = malloc(sizeof(TZX_FILE)); + + if (pTZXFile!=NULL) + { + /* set version */ + pTZXFile->VersionMajor = VersionMajor; + pTZXFile->VersionMinor = VersionMinor; + + /* initialise block linked list */ + pTZXFile->pFirstBlock = NULL; + } + + return pTZXFile; +} + +/*******************/ +/* free a TZX file */ + +void TZX_FreeFile(TZX_FILE *pFile) +{ + TZX_BLOCK *pBlock; + + pBlock = pFile->pFirstBlock; + + while (pBlock!=NULL) + { + TZX_BLOCK *pNextBlock = pBlock->pNext; + + /* remove block from list */ + TZX_DetachBlock(pFile, pBlock); + + /* free TZX block */ + TZX_FreeBlock(pBlock); + + pBlock = pNextBlock; + } + + /* free TZX file header */ + free(pFile); +} + +/*****************************************************************************************************/ +/* write a TZX file */ + +void TZX_WriteBlocks(TZX_FILE *pTZXFile, FILE *fh) +{ + TZX_BLOCK *pBlock; + + /* get pointer to first block */ + pBlock = pTZXFile->pFirstBlock; + + /* write each block in turn to file */ + while (pBlock!=NULL) + { + if (pBlock->pBlockHeader!=NULL) + { + BOOL BlockHasData; + int BlockHeaderSize; + unsigned char BlockID; + + /* get block ID */ + BlockID = pBlock->pBlockHeader[0]; + /* get size of header */ + BlockHeaderSize = TZX_GetBlockHeaderSize(BlockID); + /* does block have additional data ? */ + BlockHasData = TZX_BlockHasData(BlockID); + + if ((!BlockHasData) || ((BlockHasData) && (pBlock->pBlockData!=NULL))) + { + /* block requires data and has data, or block doesn't require data */ + + /* write the header */ + fwrite(pBlock->pBlockHeader, BlockHeaderSize, sizeof(unsigned char), fh); + + if (pBlock->pBlockData!=NULL) + { + /* write the data */ + + fwrite(pBlock->pBlockData, pBlock->DataBlockSize, sizeof(unsigned char), fh); + } + } + } + + /* next block */ + pBlock = pBlock->pNext; + } +} + + +void TZX_AppendFile(TZX_FILE *pTZXFile, unsigned char *pFilename) +{ + FILE *fh; + + /* open TZX file */ + fh = fopen((const char *)pFilename,"r+b"); + + if (fh!=NULL) + { + TZX_BLOCK *pBlock; + + fseek(fh, 0, SEEK_END); + + TZX_WriteBlocks(pTZXFile, fh); + + /* close TZX file */ + fclose(fh); + } +} + + +void TZX_WriteFile(TZX_FILE *pTZXFile, unsigned char *pFilename) +{ + FILE *fh; + + /* open TZX file */ + fh = fopen((const char *)pFilename,"wb"); + + if (fh!=NULL) + { + TZX_BLOCK *pBlock; + + /* write header */ + fwrite(TZX_FileHeader, 8, sizeof(unsigned char), fh); + /* write version numbers */ + fwrite(&pTZXFile->VersionMajor, 1, sizeof(unsigned char), fh); + fwrite(&pTZXFile->VersionMinor, 1, sizeof(unsigned char), fh); + + TZX_WriteBlocks(pTZXFile, fh); + + /* close TZX file */ + fclose(fh); + } +} + +void TZX_SetupPauseBlock(TZX_BLOCK *pBlock,unsigned long PauseInMilliseconds) +{ + unsigned char *pHeader = TZX_GetBlockHeaderPtr(pBlock); + + if (pHeader!=NULL) + { + if (pHeader[0] == TZX_PAUSE_BLOCK) + { + pHeader[1] = (unsigned char)PauseInMilliseconds; + pHeader[2] = (unsigned char)(PauseInMilliseconds>>8); + } + } +} + +/*****************************************************************************************************/ + +/* given a TZX block ID, this returns the size of the header */ +int TZX_GetBlockHeaderSize(unsigned char ID) +{ + switch (ID) + { + case TZX_STANDARD_SPEED_DATA_BLOCK: + return 4+1; + case TZX_TURBO_LOADING_DATA_BLOCK: + return 18+1; + + case TZX_PAUSE_BLOCK: + return 2+1; + case TZX_PURE_DATA_BLOCK: + return 0x0a + 1; + case TZX_DIRECT_RECORDING_BLOCK: + return 0x08 + 1; + + default: + break; + } + + return 0; +} + +/*****************************************************************************************************/ +/* return TRUE if the block has additional data, false if not */ +BOOL TZX_BlockHasData(unsigned char ID) +{ + switch (ID) + { + case TZX_STANDARD_SPEED_DATA_BLOCK: + case TZX_TURBO_LOADING_DATA_BLOCK: + case TZX_PURE_DATA_BLOCK: + case TZX_DIRECT_RECORDING_BLOCK: + return TRUE; + + case TZX_PAUSE_BLOCK: + return FALSE; + + default: + break; + } + + return FALSE; + +} + +/*****************************************************************************************************/ +/* set block size */ +void TZX_SetBlockSizeInHeader(TZX_BLOCK *pBlock, unsigned long Size) +{ + unsigned char ID = pBlock->pBlockHeader[0]; + unsigned char *pBlockData; + + pBlockData = &pBlock->pBlockHeader[1]; + + switch (ID) + { + case TZX_STANDARD_SPEED_DATA_BLOCK: + { + pBlockData[2] = (unsigned char)Size; + pBlockData[3] = (unsigned char)(Size>>8); + + } + break; + + case TZX_TURBO_LOADING_DATA_BLOCK: + { + pBlockData[0x0f] = (unsigned char)Size; + pBlockData[0x010] = (unsigned char)(Size>>8); + pBlockData[0x011] = (unsigned char)(Size>>16); + + } + break; + + case TZX_PURE_DATA_BLOCK: + { + pBlockData[0x07] = (unsigned char)Size; + pBlockData[0x08] = (unsigned char)(Size>>8); + pBlockData[0x09] = (unsigned char)(Size>>16); + } + break; + + case TZX_DIRECT_RECORDING_BLOCK: + { + pBlockData[0x05] = (unsigned char)Size; + pBlockData[0x06] = (unsigned char)(Size>>8); + pBlockData[0x07] = (unsigned char)(Size>>16); + } + break; + + default: + break; + } +} + + +/*****************************************************************************************************/ +/* create a block of the specified ID in the TZX image file */ +TZX_BLOCK *TZX_CreateBlock(unsigned char ID) +{ + TZX_BLOCK *pBlock; + + pBlock = malloc(sizeof(TZX_BLOCK)); + + if (pBlock!=NULL) + { + int BlockHeaderSize; + + /* reset block data */ + memset(pBlock, 0, sizeof(TZX_BLOCK)); + + BlockHeaderSize = TZX_GetBlockHeaderSize(ID); + + pBlock->pBlockHeader = malloc(BlockHeaderSize); + + if (pBlock->pBlockHeader!=NULL) + { + pBlock->pBlockHeader[0] = ID; + } + } + + return pBlock; +} + +/*****************************************************************************************************/ +/* create a block of the specified ID in the TZX image file */ +void TZX_AddDataToBlock(TZX_BLOCK *pBlock, int DataSize) +{ + /* only add data if a header exists */ + if (pBlock->pBlockHeader!=NULL) + { + /* get block id */ + unsigned char BlockID = pBlock->pBlockHeader[0]; + + /* does this block ID have additional data? */ + if (TZX_BlockHasData(BlockID)) + { + /* allocate memory for the additional data */ + pBlock->pBlockData = malloc(DataSize); + + if (pBlock->pBlockData!=NULL) + { + pBlock->DataBlockSize = DataSize; + + /* set size in TZX header */ + TZX_SetBlockSizeInHeader(pBlock, DataSize); + } + } + } +} + +/*****************************************************************************************************/ +/* get pointer to TZX data block */ +unsigned char *TZX_GetBlockDataPtr(TZX_BLOCK *pBlock) +{ + return pBlock->pBlockData; +} + +/*****************************************************************************************************/ +/* get pointer to TZX data block */ +unsigned char *TZX_GetBlockHeaderPtr(TZX_BLOCK *pBlock) +{ + return pBlock->pBlockHeader; +} diff --git a/tools/2CDT/src/tzxfile.h b/tools/2CDT/src/tzxfile.h new file mode 100644 index 0000000..397f5d1 --- /dev/null +++ b/tools/2CDT/src/tzxfile.h @@ -0,0 +1,79 @@ +/* + * 2CDT Copyright (c) Kevin Thacker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __TZX_FILE_HEADER__ +#define __TZX_FILE_HEADER__ + +#include "defs.h" + +#define TZX_VERSION_MAJOR 1 +#define TZX_VERSION_MINOR 10 + +#define TZX_STANDARD_SPEED_DATA_BLOCK 0x010 +#define TZX_TURBO_LOADING_DATA_BLOCK 0x011 +#define TZX_PAUSE_BLOCK 0x020 +#define TZX_PURE_DATA_BLOCK 0x014 +#define TZX_DIRECT_RECORDING_BLOCK 0x015 + +#define TZX_T_STATES 3500000 + + +#define TZX_HARDWARE_COMPUTER_CPC464 0x015 /* Amstrad CPC 464 */ +#define TZX_HARDWARE_COMPUTER_CPC664 0x016 /* Amstrad CPC 664 */ +#define TZX_HARDWARE_COMPUTER_CPC6128 0x017 /* Amstrad CPC 6128 */ +#define TZX_HARDWARE_COMPUTER_CPC464PLUS 0x018 /* Amstrad CPC 464+ */ +#define TZX_HARDWARE_COMPUTER_CPC6128PLUS 0x019 /* Amstrad CPC 6128+ */ + +typedef struct TZX_BLOCK +{ + /* previous TZX block */ + struct TZX_BLOCK *pPrev; + /* next TZX block */ + struct TZX_BLOCK *pNext; + /* pointer to header data allocated for this block */ + unsigned char *pBlockHeader; + /* size of data block */ + unsigned long DataBlockSize; + /* pointer to data added to this block */ + unsigned char *pBlockData; +} TZX_BLOCK; + +typedef struct TZX_FILE +{ + /* version of TZX file */ + unsigned char VersionMajor; + unsigned char VersionMinor; + /* pointer to first block */ + TZX_BLOCK *pFirstBlock; +} TZX_FILE; + +void TZX_WriteFile(TZX_FILE *pTZXFile, unsigned char *pFilename); +unsigned char *TZX_GetBlockDataPtr(TZX_BLOCK *); +unsigned char *TZX_GetBlockHeaderPtr(TZX_BLOCK *); + +TZX_FILE *TZX_CreateFile(unsigned char VersionMajor, unsigned char VersionMinor); +void TZX_FreeFile(TZX_FILE *pFile); +void TZX_AddDataToBlock(TZX_BLOCK *pBlock, int DataSize); +unsigned char *TZX_GetDataBlockPtr(TZX_BLOCK *pBlock); +void TZX_AddBlockToEndOfFile(TZX_FILE *pFile, TZX_BLOCK *pBlock); +int TZX_GetBlockHeaderSize(unsigned char ID); +BOOL TZX_BlockHasData(unsigned char ID); +TZX_BLOCK *TZX_CreateBlock(unsigned char ID); +void TZX_SetupPauseBlock(TZX_BLOCK *pBlock,unsigned long PauseInMilliseconds); +#endif + diff --git a/tools/Makefile b/tools/Makefile new file mode 100644 index 0000000..fa59614 --- /dev/null +++ b/tools/Makefile @@ -0,0 +1,38 @@ +BIN=idsk 2cdt ucl png2crtc hex2bin + +all: $(BIN) +CC=gcc +CFLAGS=-s -O3 -Wall + +idsk: + mkdir iDSK/build + cd iDSK/build && cmake ../ + make -C iDSK/build + cp iDSK/build/iDSK idsk + rm -rf iDSK/build + +2cdt: + make -C 2CDT + cp 2CDT/2cdt . + +png2crtc: + make -C gfx2crtc + cp gfx2crtc/png2crtc . + +%.o: %.c + $(CC) $(CFLAGS) $< -o $@ -c + +ucl: ucl.o + $(CC) -lucl $< -o $@ + +hex2bin: + make -C hex2bin-2.0 + cp hex2bin-2.0/bin/hex2bin . + +.PHONY: clean +clean: + make -C 2CDT clean + make -C gfx2crtc clean + make -C hex2bin-2.0 clean + rm -f $(BIN) *.o + diff --git a/tools/README.ucl b/tools/README.ucl new file mode 100644 index 0000000..ade95f9 --- /dev/null +++ b/tools/README.ucl @@ -0,0 +1,7 @@ +This is a simple compressor using the UCL library. + +It takes the data from stdin and writes to stdout. + +It is limited to MAX_MEM (64kb), but you should be compressing +way less than that anyway! + diff --git a/tools/bin2h.py b/tools/bin2h.py new file mode 100755 index 0000000..c430538 --- /dev/null +++ b/tools/bin2h.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python + +from argparse import ArgumentParser + +__version__ = "1.0" + +def main(): + + parser = ArgumentParser(description="Bin to H converter", + epilog="Copyright (C) 2014 Juan J Martinez ", + ) + + parser.add_argument("--version", action="version", version="%(prog)s " + __version__) + parser.add_argument("file", help="file to convert") + parser.add_argument("id", help="variable to use") + + args = parser.parse_args() + + with open(args.file, "rb") as fd: + data = bytearray(fd.read()) + + data_out = "" + for part in range(0, len(data), 8): + if data_out: + data_out += ",\n" + data_out += ', '.join(["0x%02x" % b for b in data[part: part + 8]]) + + print("/* file: %s */" % args.file) + print("#define %s_LEN %d\n" % (args.id.upper(), len(data))) + print("const unsigned char %s[] = {\n%s\n};\n" % (args.id, data_out)) + +if __name__ == "__main__": + main() + diff --git a/tools/chksize b/tools/chksize new file mode 100755 index 0000000..6f2c9b8 --- /dev/null +++ b/tools/chksize @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 + +import sys + +# video memory + back buffer (stack in 0x200) +TOP_MEM = 0xc000 + + +def main(): + if len(sys.argv) != 3: + sys.exit("usage: %s load_addr filename.map" % sys.argv[0]) + + load_addr = int(sys.argv[1]) + + with open(sys.argv[2], "r") as fd: + lines = fd.readlines() + # warnings + for line in lines: + if "l__INITIALIZED" in line: + init_size = int(line.split()[0], base=16) + if init_size != 0: + print("*WARNING* Initialized data found") + # search for HEAP + for line in lines: + if "s__HEAP" in line: + heap_addr = int(line.split()[0], base=16) + max_mem = TOP_MEM - load_addr + cur_mem = heap_addr - load_addr + left_mem = max_mem - cur_mem + print("""\ +*** + Max: {} bytes + Current: {} bytes ({} bytes left) +*** +""".format(max_mem, cur_mem, left_mem)) + sys.exit(0) + + sys.exit("HEAP size not found") + + +if __name__ == "__main__": + main() diff --git a/tools/dump-pal.py b/tools/dump-pal.py new file mode 100755 index 0000000..c87d7e7 --- /dev/null +++ b/tools/dump-pal.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python + +__version__ = "1.0" + +from argparse import ArgumentParser +from PIL import Image + +# firmware +CPC_PAL = ( + [0, 0, 0], + [0, 0, 128], + [0, 0, 255], + [128, 0, 0], + [128, 0, 128], + [128, 0, 255], + [255, 0, 0], + [255, 0, 128], + [255, 0, 255], + [0, 128, 0], + [0, 128, 128], + [0, 128, 255], + [128, 128, 0], + [128, 128, 128], + [128, 128, 255], + [255, 128, 0], + [255, 128, 128], + [255, 128, 255], + [0, 255, 0], + [0, 255, 128], + [0, 255, 255], + [128, 255, 0], + [128, 255, 128], + [128, 255, 255], + [255, 255, 0], + [255, 255, 128], + [255, 255, 255], + ) + +# hardware +CPC_PAL_HW = ( + 0x54, 0x44, 0x55, 0x5c, 0x58, 0x5d, 0x4c, 0x45, 0x4d, + 0x56, 0x46, 0x57, 0x5e, 0x40, 0x5f, 0x4e, 0x47, 0x4f, + 0x52, 0x42, 0x53, 0x5a, 0x59, 0x5b, 0x4a, 0x43, 0x4b, + ) + +def main(): + + parser = ArgumentParser(description="PNG to CPC palette (firmware)", + epilog="Copyright (C) 2015 Juan J Martinez ", + ) + + parser.add_argument("--version", action="version", version="%(prog)s " + __version__) + parser.add_argument("--hw", action="store_true", dest="hardware") + parser.add_argument("image", help="image to convert") + parser.add_argument("pal_dump", help="filename for the palette dump") + + args = parser.parse_args() + + try: + image = Image.open(args.image) + except IOError: + parser.error("failed to open the image") + + if image.mode != "P": + parser.error("not an indexed image (no palette)") + + palette = image.getpalette() + if not palette: + parser.error("failed to extract the palette (is this an indexed image?)") + + colors = image.getcolors(maxcolors=16) + if not colors: + parser.error("failed to extract the palette (color limit is 16)") + + rgb = [] + for _, i in colors: + c = palette[i * 3:i * 3 + 3] + if c not in CPC_PAL: + parser.error("%r not in the CPC palette" % c) + if c not in rgb: + rgb.append(c) + + out = [CPC_PAL.index(c) for c in rgb] + if len(out) < 16: + out.extend([i for i in range(16 - len(out))]) + + if args.hardware: + out = [CPC_PAL_HW[c] for c in out] + + with open(args.pal_dump, "wb") as fd: + fd.write(bytearray(out)) + +if __name__ == "__main__": + main() + diff --git a/tools/encrypt.py b/tools/encrypt.py new file mode 100644 index 0000000..6e03336 --- /dev/null +++ b/tools/encrypt.py @@ -0,0 +1,25 @@ + +def enc(key, text): + p = 0x59 + r = [] + for c in text: + new = ((ord(c) ^ p) ^ key) & 0xff + r.append(new) + p = new + return r + +def dec(key, text): + p = 0x59 + r = [] + for c in text: + new = ((c ^ key) ^ p) & 0xff + r.append(new) + p = c + return r + +res = enc(0xfe, "THE WAR IS OVER AND\nWE PREVAILED.\n\nFOR NOW...\n\nYOU ARE A LEGEND!\n\nTHANKS FOR PLAYING\nTHE GAME.\0") +print ", ".join("0x%02x" % r for r in res) + +res = dec(0xfe, res) +print "".join(chr(r) for r in res) + diff --git a/tools/gfx2crtc/AUTHORS b/tools/gfx2crtc/AUTHORS new file mode 100644 index 0000000..4cb7787 --- /dev/null +++ b/tools/gfx2crtc/AUTHORS @@ -0,0 +1,5 @@ +Logiciel Initial : +CloudStrife/Shinra (Quentin Carlier) + +Contributors: +PulkoMandy/Shinra (Adrien Destugues) diff --git a/tools/gfx2crtc/LICENCE b/tools/gfx2crtc/LICENCE new file mode 100644 index 0000000..1613fca --- /dev/null +++ b/tools/gfx2crtc/LICENCE @@ -0,0 +1,512 @@ + +CONTRAT DE LICENCE DE LOGICIEL LIBRE CeCILL + + + Avertissement + +Ce contrat est une licence de logiciel libre issue d'une concertation +entre ses auteurs afin que le respect de deux grands principes prside +sa rdaction: + + * d'une part, le respect des principes de diffusion des logiciels + libres: accs au code source, droits tendus confrs aux + utilisateurs, + * d'autre part, la dsignation d'un droit applicable, le droit + franais, auquel elle est conforme, tant au regard du droit de la + responsabilit civile que du droit de la proprit intellectuelle + et de la protection qu'il offre aux auteurs et titulaires des + droits patrimoniaux sur un logiciel. + +Les auteurs de la licence CeCILL (pour Ce[a] C[nrs] I[nria] L[ogiciel] +L[ibre]) sont: + +Commissariat l'Energie Atomique - CEA, tablissement public de +recherche caractre scientifique, technique et industriel, dont le +sige est situ 25 rue Leblanc, immeuble Le Ponant D, 75015 Paris. + +Centre National de la Recherche Scientifique - CNRS, tablissement +public caractre scientifique et technologique, dont le sige est +situ 3 rue Michel-Ange, 75794 Paris cedex 16. + +Institut National de Recherche en Informatique et en Automatique - +INRIA, tablissement public caractre scientifique et technologique, +dont le sige est situ Domaine de Voluceau, Rocquencourt, BP 105, 78153 +Le Chesnay cedex. + + + Prambule + +Ce contrat est une licence de logiciel libre dont l'objectif est de +confrer aux utilisateurs la libert de modification et de +redistribution du logiciel rgi par cette licence dans le cadre d'un +modle de diffusion en logiciel libre. + +L'exercice de ces liberts est assorti de certains devoirs la charge +des utilisateurs afin de prserver ce statut au cours des +redistributions ultrieures. + +L'accessibilit au code source et les droits de copie, de modification +et de redistribution qui en dcoulent ont pour contrepartie de n'offrir +aux utilisateurs qu'une garantie limite et de ne faire peser sur +l'auteur du logiciel, le titulaire des droits patrimoniaux et les +concdants successifs qu'une responsabilit restreinte. + +A cet gard l'attention de l'utilisateur est attire sur les risques +associs au chargement, l'utilisation, la modification et/ou au +dveloppement et la reproduction du logiciel par l'utilisateur tant +donn sa spcificit de logiciel libre, qui peut le rendre complexe +manipuler et qui le rserve donc des dveloppeurs ou des +professionnels avertis possdant des connaissances informatiques +approfondies. Les utilisateurs sont donc invits charger et tester +l'adquation du logiciel leurs besoins dans des conditions permettant +d'assurer la scurit de leurs systmes et/ou de leurs donnes et, plus +gnralement, l'utiliser et l'exploiter dans les mmes conditions de +scurit. Ce contrat peut tre reproduit et diffus librement, sous +rserve de le conserver en l'tat, sans ajout ni suppression de clauses. + +Ce contrat est susceptible de s'appliquer tout logiciel dont le +titulaire des droits patrimoniaux dcide de soumettre l'exploitation aux +dispositions qu'il contient. + + + Article 1 - DEFINITIONS + +Dans ce contrat, les termes suivants, lorsqu'ils seront crits avec une +lettre capitale, auront la signification suivante: + +Contrat: dsigne le prsent contrat de licence, ses ventuelles versions +postrieures et annexes. + +Logiciel: dsigne le logiciel sous sa forme de Code Objet et/ou de Code +Source et le cas chant sa documentation, dans leur tat au moment de +l'acceptation du Contrat par le Licenci. + +Logiciel Initial: dsigne le Logiciel sous sa forme de Code Source et +ventuellement de Code Objet et le cas chant sa documentation, dans +leur tat au moment de leur premire diffusion sous les termes du Contrat. + +Logiciel Modifi: dsigne le Logiciel modifi par au moins une +Contribution. + +Code Source: dsigne l'ensemble des instructions et des lignes de +programme du Logiciel et auquel l'accs est ncessaire en vue de +modifier le Logiciel. + +Code Objet: dsigne les fichiers binaires issus de la compilation du +Code Source. + +Titulaire: dsigne le ou les dtenteurs des droits patrimoniaux d'auteur +sur le Logiciel Initial. + +Licenci: dsigne le ou les utilisateurs du Logiciel ayant accept le +Contrat. + +Contributeur: dsigne le Licenci auteur d'au moins une Contribution. + +Concdant: dsigne le Titulaire ou toute personne physique ou morale +distribuant le Logiciel sous le Contrat. + +Contribution: dsigne l'ensemble des modifications, corrections, +traductions, adaptations et/ou nouvelles fonctionnalits intgres dans +le Logiciel par tout Contributeur, ainsi que tout Module Interne. + +Module: dsigne un ensemble de fichiers sources y compris leur +documentation qui permet de raliser des fonctionnalits ou services +supplmentaires ceux fournis par le Logiciel. + +Module Externe: dsigne tout Module, non driv du Logiciel, tel que ce +Module et le Logiciel s'excutent dans des espaces d'adressage +diffrents, l'un appelant l'autre au moment de leur excution. + +Module Interne: dsigne tout Module li au Logiciel de telle sorte +qu'ils s'excutent dans le mme espace d'adressage. + +GNU GPL: dsigne la GNU General Public License dans sa version 2 ou +toute version ultrieure, telle que publie par Free Software Foundation +Inc. + +Parties: dsigne collectivement le Licenci et le Concdant. + +Ces termes s'entendent au singulier comme au pluriel. + + + Article 2 - OBJET + +Le Contrat a pour objet la concession par le Concdant au Licenci d'une +licence non exclusive, cessible et mondiale du Logiciel telle que +dfinie ci-aprs l'article 5 pour toute la dure de protection des droits +portant sur ce Logiciel. + + + Article 3 - ACCEPTATION + +3.1 L'acceptation par le Licenci des termes du Contrat est rpute +acquise du fait du premier des faits suivants: + + * (i) le chargement du Logiciel par tout moyen notamment par + tlchargement partir d'un serveur distant ou par chargement + partir d'un support physique; + * (ii) le premier exercice par le Licenci de l'un quelconque des + droits concds par le Contrat. + +3.2 Un exemplaire du Contrat, contenant notamment un avertissement +relatif aux spcificits du Logiciel, la restriction de garantie et +la limitation un usage par des utilisateurs expriments a t mis +disposition du Licenci pralablement son acceptation telle que +dfinie l'article 3.1 ci dessus et le Licenci reconnat en avoir pris +connaissance. + + + Article 4 - ENTREE EN VIGUEUR ET DUREE + + + 4.1 ENTREE EN VIGUEUR + +Le Contrat entre en vigueur la date de son acceptation par le Licenci +telle que dfinie en 3.1. + + + 4.2 DUREE + +Le Contrat produira ses effets pendant toute la dure lgale de +protection des droits patrimoniaux portant sur le Logiciel. + + + Article 5 - ETENDUE DES DROITS CONCEDES + +Le Concdant concde au Licenci, qui accepte, les droits suivants sur +le Logiciel pour toutes destinations et pour la dure du Contrat dans +les conditions ci-aprs dtailles. + +Par ailleurs, si le Concdant dtient ou venait dtenir un ou +plusieurs brevets d'invention protgeant tout ou partie des +fonctionnalits du Logiciel ou de ses composants, il s'engage ne pas +opposer les ventuels droits confrs par ces brevets aux Licencis +successifs qui utiliseraient, exploiteraient ou modifieraient le +Logiciel. En cas de cession de ces brevets, le Concdant s'engage +faire reprendre les obligations du prsent alina aux cessionnaires. + + + 5.1 DROIT D'UTILISATION + +Le Licenci est autoris utiliser le Logiciel, sans restriction quant +aux domaines d'application, tant ci-aprs prcis que cela comporte: + + 1. la reproduction permanente ou provisoire du Logiciel en tout ou + partie par tout moyen et sous toute forme. + + 2. le chargement, l'affichage, l'excution, ou le stockage du + Logiciel sur tout support. + + 3. la possibilit d'en observer, d'en tudier, ou d'en tester le + fonctionnement afin de dterminer les ides et principes qui sont + la base de n'importe quel lment de ce Logiciel; et ceci, + lorsque le Licenci effectue toute opration de chargement, + d'affichage, d'excution, de transmission ou de stockage du + Logiciel qu'il est en droit d'effectuer en vertu du Contrat. + + + 5.2 DROIT D'APPORTER DES CONTRIBUTIONS + +Le droit d'apporter des Contributions comporte le droit de traduire, +d'adapter, d'arranger ou d'apporter toute autre modification au Logiciel +et le droit de reproduire le logiciel en rsultant. + +Le Licenci est autoris apporter toute Contribution au Logiciel sous +rserve de mentionner, de faon explicite, son nom en tant qu'auteur de +cette Contribution et la date de cration de celle-ci. + + + 5.3 DROIT DE DISTRIBUTION + +Le droit de distribution comporte notamment le droit de diffuser, de +transmettre et de communiquer le Logiciel au public sur tout support et +par tout moyen ainsi que le droit de mettre sur le march titre +onreux ou gratuit, un ou des exemplaires du Logiciel par tout procd. + +Le Licenci est autoris distribuer des copies du Logiciel, modifi ou +non, des tiers dans les conditions ci-aprs dtailles. + + + 5.3.1 DISTRIBUTION DU LOGICIEL SANS MODIFICATION + +Le Licenci est autoris distribuer des copies conformes du Logiciel, +sous forme de Code Source ou de Code Objet, condition que cette +distribution respecte les dispositions du Contrat dans leur totalit et +soit accompagne: + + 1. d'un exemplaire du Contrat, + + 2. d'un avertissement relatif la restriction de garantie et de + responsabilit du Concdant telle que prvue aux articles 8 + et 9, + +et que, dans le cas o seul le Code Objet du Logiciel est redistribu, +le Licenci permette aux futurs Licencis d'accder facilement au Code +Source complet du Logiciel en indiquant les modalits d'accs, tant +entendu que le cot additionnel d'acquisition du Code Source ne devra +pas excder le simple cot de transfert des donnes. + + + 5.3.2 DISTRIBUTION DU LOGICIEL MODIFIE + +Lorsque le Licenci apporte une Contribution au Logiciel, les conditions +de distribution du Logiciel Modifi en rsultant sont alors soumises +l'intgralit des dispositions du Contrat. + +Le Licenci est autoris distribuer le Logiciel Modifi, sous forme de +code source ou de code objet, condition que cette distribution +respecte les dispositions du Contrat dans leur totalit et soit +accompagne: + + 1. d'un exemplaire du Contrat, + + 2. d'un avertissement relatif la restriction de garantie et de + responsabilit du Concdant telle que prvue aux articles 8 + et 9, + +et que, dans le cas o seul le code objet du Logiciel Modifi est +redistribu, le Licenci permette aux futurs Licencis d'accder +facilement au code source complet du Logiciel Modifi en indiquant les +modalits d'accs, tant entendu que le cot additionnel d'acquisition +du code source ne devra pas excder le simple cot de transfert des donnes. + + + 5.3.3 DISTRIBUTION DES MODULES EXTERNES + +Lorsque le Licenci a dvelopp un Module Externe les conditions du +Contrat ne s'appliquent pas ce Module Externe, qui peut tre distribu +sous un contrat de licence diffrent. + + + 5.3.4 COMPATIBILITE AVEC LA LICENCE GNU GPL + +Le Licenci peut inclure un code soumis aux dispositions d'une des +versions de la licence GNU GPL dans le Logiciel modifi ou non et +distribuer l'ensemble sous les conditions de la mme version de la +licence GNU GPL. + +Le Licenci peut inclure le Logiciel modifi ou non dans un code soumis +aux dispositions d'une des versions de la licence GNU GPL et distribuer +l'ensemble sous les conditions de la mme version de la licence GNU GPL. + + + Article 6 - PROPRIETE INTELLECTUELLE + + + 6.1 SUR LE LOGICIEL INITIAL + +Le Titulaire est dtenteur des droits patrimoniaux sur le Logiciel +Initial. Toute utilisation du Logiciel Initial est soumise au respect +des conditions dans lesquelles le Titulaire a choisi de diffuser son +oeuvre et nul autre n'a la facult de modifier les conditions de +diffusion de ce Logiciel Initial. + +Le Titulaire s'engage ce que le Logiciel Initial reste au moins rgi +par le Contrat et ce, pour la dure vise l'article 4.2. + + + 6.2 SUR LES CONTRIBUTIONS + +Le Licenci qui a dvelopp une Contribution est titulaire sur celle-ci +des droits de proprit intellectuelle dans les conditions dfinies par +la lgislation applicable. + + + 6.3 SUR LES MODULES EXTERNES + +Le Licenci qui a dvelopp un Module Externe est titulaire sur celui-ci +des droits de proprit intellectuelle dans les conditions dfinies par +la lgislation applicable et reste libre du choix du contrat rgissant +sa diffusion. + + + 6.4 DISPOSITIONS COMMUNES + +Le Licenci s'engage expressment: + + 1. ne pas supprimer ou modifier de quelque manire que ce soit les + mentions de proprit intellectuelle apposes sur le Logiciel; + + 2. reproduire l'identique lesdites mentions de proprit + intellectuelle sur les copies du Logiciel modifi ou non. + +Le Licenci s'engage ne pas porter atteinte, directement ou +indirectement, aux droits de proprit intellectuelle du Titulaire et/ou +des Contributeurs sur le Logiciel et prendre, le cas chant, +l'gard de son personnel toutes les mesures ncessaires pour assurer le +respect des dits droits de proprit intellectuelle du Titulaire et/ou +des Contributeurs. + + + Article 7 - SERVICES ASSOCIES + +7.1 Le Contrat n'oblige en aucun cas le Concdant la ralisation de +prestations d'assistance technique ou de maintenance du Logiciel. + +Cependant le Concdant reste libre de proposer ce type de services. Les +termes et conditions d'une telle assistance technique et/ou d'une telle +maintenance seront alors dtermins dans un acte spar. Ces actes de +maintenance et/ou assistance technique n'engageront que la seule +responsabilit du Concdant qui les propose. + +7.2 De mme, tout Concdant est libre de proposer, sous sa seule +responsabilit, ses licencis une garantie, qui n'engagera que lui, +lors de la redistribution du Logiciel et/ou du Logiciel Modifi et ce, +dans les conditions qu'il souhaite. Cette garantie et les modalits +financires de son application feront l'objet d'un acte spar entre le +Concdant et le Licenci. + + + Article 8 - RESPONSABILITE + +8.1 Sous rserve des dispositions de l'article 8.2, le Licenci a la +facult, sous rserve de prouver la faute du Concdant concern, de +solliciter la rparation du prjudice direct qu'il subirait du fait du +Logiciel et dont il apportera la preuve. + +8.2 La responsabilit du Concdant est limite aux engagements pris en +application du Contrat et ne saurait tre engage en raison notamment: +(i) des dommages dus l'inexcution, totale ou partielle, de ses +obligations par le Licenci, (ii) des dommages directs ou indirects +dcoulant de l'utilisation ou des performances du Logiciel subis par le +Licenci et (iii) plus gnralement d'un quelconque dommage indirect. En +particulier, les Parties conviennent expressment que tout prjudice +financier ou commercial (par exemple perte de donnes, perte de +bnfices, perte d'exploitation, perte de clientle ou de commandes, +manque gagner, trouble commercial quelconque) ou toute action dirige +contre le Licenci par un tiers, constitue un dommage indirect et +n'ouvre pas droit rparation par le Concdant. + + + Article 9 - GARANTIE + +9.1 Le Licenci reconnat que l'tat actuel des connaissances +scientifiques et techniques au moment de la mise en circulation du +Logiciel ne permet pas d'en tester et d'en vrifier toutes les +utilisations ni de dtecter l'existence d'ventuels dfauts. L'attention +du Licenci a t attire sur ce point sur les risques associs au +chargement, l'utilisation, la modification et/ou au dveloppement et +la reproduction du Logiciel qui sont rservs des utilisateurs avertis. + +Il relve de la responsabilit du Licenci de contrler, par tous +moyens, l'adquation du produit ses besoins, son bon fonctionnement et +de s'assurer qu'il ne causera pas de dommages aux personnes et aux biens. + +9.2 Le Concdant dclare de bonne foi tre en droit de concder +l'ensemble des droits attachs au Logiciel (comprenant notamment les +droits viss l'article 5). + +9.3 Le Licenci reconnat que le Logiciel est fourni "en l'tat" par le +Concdant sans autre garantie, expresse ou tacite, que celle prvue +l'article 9.2 et notamment sans aucune garantie sur sa valeur commerciale, +son caractre scuris, innovant ou pertinent. + +En particulier, le Concdant ne garantit pas que le Logiciel est exempt +d'erreur, qu'il fonctionnera sans interruption, qu'il sera compatible +avec l'quipement du Licenci et sa configuration logicielle ni qu'il +remplira les besoins du Licenci. + +9.4 Le Concdant ne garantit pas, de manire expresse ou tacite, que le +Logiciel ne porte pas atteinte un quelconque droit de proprit +intellectuelle d'un tiers portant sur un brevet, un logiciel ou sur tout +autre droit de proprit. Ainsi, le Concdant exclut toute garantie au +profit du Licenci contre les actions en contrefaon qui pourraient tre +diligentes au titre de l'utilisation, de la modification, et de la +redistribution du Logiciel. Nanmoins, si de telles actions sont +exerces contre le Licenci, le Concdant lui apportera son aide +technique et juridique pour sa dfense. Cette aide technique et +juridique est dtermine au cas par cas entre le Concdant concern et +le Licenci dans le cadre d'un protocole d'accord. Le Concdant dgage +toute responsabilit quant l'utilisation de la dnomination du +Logiciel par le Licenci. Aucune garantie n'est apporte quant +l'existence de droits antrieurs sur le nom du Logiciel et sur +l'existence d'une marque. + + + Article 10 - RESILIATION + +10.1 En cas de manquement par le Licenci aux obligations mises sa +charge par le Contrat, le Concdant pourra rsilier de plein droit le +Contrat trente (30) jours aprs notification adresse au Licenci et +reste sans effet. + +10.2 Le Licenci dont le Contrat est rsili n'est plus autoris +utiliser, modifier ou distribuer le Logiciel. Cependant, toutes les +licences qu'il aura concdes antrieurement la rsiliation du Contrat +resteront valides sous rserve qu'elles aient t effectues en +conformit avec le Contrat. + + + Article 11 - DISPOSITIONS DIVERSES + + + 11.1 CAUSE EXTERIEURE + +Aucune des Parties ne sera responsable d'un retard ou d'une dfaillance +d'excution du Contrat qui serait d un cas de force majeure, un cas +fortuit ou une cause extrieure, telle que, notamment, le mauvais +fonctionnement ou les interruptions du rseau lectrique ou de +tlcommunication, la paralysie du rseau lie une attaque +informatique, l'intervention des autorits gouvernementales, les +catastrophes naturelles, les dgts des eaux, les tremblements de terre, +le feu, les explosions, les grves et les conflits sociaux, l'tat de +guerre... + +11.2 Le fait, par l'une ou l'autre des Parties, d'omettre en une ou +plusieurs occasions de se prvaloir d'une ou plusieurs dispositions du +Contrat, ne pourra en aucun cas impliquer renonciation par la Partie +intresse s'en prvaloir ultrieurement. + +11.3 Le Contrat annule et remplace toute convention antrieure, crite +ou orale, entre les Parties sur le mme objet et constitue l'accord +entier entre les Parties sur cet objet. Aucune addition ou modification +aux termes du Contrat n'aura d'effet l'gard des Parties moins +d'tre faite par crit et signe par leurs reprsentants dment habilits. + +11.4 Dans l'hypothse o une ou plusieurs des dispositions du Contrat +s'avrerait contraire une loi ou un texte applicable, existants ou +futurs, cette loi ou ce texte prvaudrait, et les Parties feraient les +amendements ncessaires pour se conformer cette loi ou ce texte. +Toutes les autres dispositions resteront en vigueur. De mme, la +nullit, pour quelque raison que ce soit, d'une des dispositions du +Contrat ne saurait entraner la nullit de l'ensemble du Contrat. + + + 11.5 LANGUE + +Le Contrat est rdig en langue franaise et en langue anglaise, ces +deux versions faisant galement foi. + + + Article 12 - NOUVELLES VERSIONS DU CONTRAT + +12.1 Toute personne est autorise copier et distribuer des copies de +ce Contrat. + +12.2 Afin d'en prserver la cohrence, le texte du Contrat est protg +et ne peut tre modifi que par les auteurs de la licence, lesquels se +rservent le droit de publier priodiquement des mises jour ou de +nouvelles versions du Contrat, qui possderont chacune un numro +distinct. Ces versions ultrieures seront susceptibles de prendre en +compte de nouvelles problmatiques rencontres par les logiciels libres. + +12.3 Tout Logiciel diffus sous une version donne du Contrat ne pourra +faire l'objet d'une diffusion ultrieure que sous la mme version du +Contrat ou une version postrieure, sous rserve des dispositions de +l'article 5.3.4. + + + Article 13 - LOI APPLICABLE ET COMPETENCE TERRITORIALE + +13.1 Le Contrat est rgi par la loi franaise. Les Parties conviennent +de tenter de rgler l'amiable les diffrends ou litiges qui +viendraient se produire par suite ou l'occasion du Contrat. + +13.2 A dfaut d'accord amiable dans un dlai de deux (2) mois compter +de leur survenance et sauf situation relevant d'une procdure d'urgence, +les diffrends ou litiges seront ports par la Partie la plus diligente +devant les Tribunaux comptents de Paris. + + +Version 2.0 du 2006-09-05. diff --git a/tools/gfx2crtc/LICENSE b/tools/gfx2crtc/LICENSE new file mode 100644 index 0000000..fcc8df2 --- /dev/null +++ b/tools/gfx2crtc/LICENSE @@ -0,0 +1,506 @@ + +CeCILL FREE SOFTWARE LICENSE AGREEMENT + + + Notice + +This Agreement is a Free Software license agreement that is the result +of discussions between its authors in order to ensure compliance with +the two main principles guiding its drafting: + + * firstly, compliance with the principles governing the distribution + of Free Software: access to source code, broad rights granted to + users, + * secondly, the election of a governing law, French law, with which + it is conformant, both as regards the law of torts and + intellectual property law, and the protection that it offers to + both authors and holders of the economic rights over software. + +The authors of the CeCILL (for Ce[a] C[nrs] I[nria] L[ogiciel] L[ibre]) +license are: + +Commissariat l'Energie Atomique - CEA, a public scientific, technical +and industrial research establishment, having its principal place of +business at 25 rue Leblanc, immeuble Le Ponant D, 75015 Paris, France. + +Centre National de la Recherche Scientifique - CNRS, a public scientific +and technological establishment, having its principal place of business +at 3 rue Michel-Ange, 75794 Paris cedex 16, France. + +Institut National de Recherche en Informatique et en Automatique - +INRIA, a public scientific and technological establishment, having its +principal place of business at Domaine de Voluceau, Rocquencourt, BP +105, 78153 Le Chesnay cedex, France. + + + Preamble + +The purpose of this Free Software license agreement is to grant users +the right to modify and redistribute the software governed by this +license within the framework of an open source distribution model. + +The exercising of these rights is conditional upon certain obligations +for users so as to preserve this status for all subsequent redistributions. + +In consideration of access to the source code and the rights to copy, +modify and redistribute granted by the license, users are provided only +with a limited warranty and the software's author, the holder of the +economic rights, and the successive licensors only have limited liability. + +In this respect, the risks associated with loading, using, modifying +and/or developing or reproducing the software by the user are brought to +the user's attention, given its Free Software status, which may make it +complicated to use, with the result that its use is reserved for +developers and experienced professionals having in-depth computer +knowledge. Users are therefore encouraged to load and test the +suitability of the software as regards their requirements in conditions +enabling the security of their systems and/or data to be ensured and, +more generally, to use and operate it in the same conditions of +security. This Agreement may be freely reproduced and published, +provided it is not altered, and that no provisions are either added or +removed herefrom. + +This Agreement may apply to any or all software for which the holder of +the economic rights decides to submit the use thereof to its provisions. + + + Article 1 - DEFINITIONS + +For the purpose of this Agreement, when the following expressions +commence with a capital letter, they shall have the following meaning: + +Agreement: means this license agreement, and its possible subsequent +versions and annexes. + +Software: means the software in its Object Code and/or Source Code form +and, where applicable, its documentation, "as is" when the Licensee +accepts the Agreement. + +Initial Software: means the Software in its Source Code and possibly its +Object Code form and, where applicable, its documentation, "as is" when +it is first distributed under the terms and conditions of the Agreement. + +Modified Software: means the Software modified by at least one +Contribution. + +Source Code: means all the Software's instructions and program lines to +which access is required so as to modify the Software. + +Object Code: means the binary files originating from the compilation of +the Source Code. + +Holder: means the holder(s) of the economic rights over the Initial +Software. + +Licensee: means the Software user(s) having accepted the Agreement. + +Contributor: means a Licensee having made at least one Contribution. + +Licensor: means the Holder, or any other individual or legal entity, who +distributes the Software under the Agreement. + +Contribution: means any or all modifications, corrections, translations, +adaptations and/or new functions integrated into the Software by any or +all Contributors, as well as any or all Internal Modules. + +Module: means a set of sources files including their documentation that +enables supplementary functions or services in addition to those offered +by the Software. + +External Module: means any or all Modules, not derived from the +Software, so that this Module and the Software run in separate address +spaces, with one calling the other when they are run. + +Internal Module: means any or all Module, connected to the Software so +that they both execute in the same address space. + +GNU GPL: means the GNU General Public License version 2 or any +subsequent version, as published by the Free Software Foundation Inc. + +Parties: mean both the Licensee and the Licensor. + +These expressions may be used both in singular and plural form. + + + Article 2 - PURPOSE + +The purpose of the Agreement is the grant by the Licensor to the +Licensee of a non-exclusive, transferable and worldwide license for the +Software as set forth in Article 5 hereinafter for the whole term of the +protection granted by the rights over said Software. + + + Article 3 - ACCEPTANCE + +3.1 The Licensee shall be deemed as having accepted the terms and +conditions of this Agreement upon the occurrence of the first of the +following events: + + * (i) loading the Software by any or all means, notably, by + downloading from a remote server, or by loading from a physical + medium; + * (ii) the first time the Licensee exercises any of the rights + granted hereunder. + +3.2 One copy of the Agreement, containing a notice relating to the +characteristics of the Software, to the limited warranty, and to the +fact that its use is restricted to experienced users has been provided +to the Licensee prior to its acceptance as set forth in Article 3.1 +hereinabove, and the Licensee hereby acknowledges that it has read and +understood it. + + + Article 4 - EFFECTIVE DATE AND TERM + + + 4.1 EFFECTIVE DATE + +The Agreement shall become effective on the date when it is accepted by +the Licensee as set forth in Article 3.1. + + + 4.2 TERM + +The Agreement shall remain in force for the entire legal term of +protection of the economic rights over the Software. + + + Article 5 - SCOPE OF RIGHTS GRANTED + +The Licensor hereby grants to the Licensee, who accepts, the following +rights over the Software for any or all use, and for the term of the +Agreement, on the basis of the terms and conditions set forth hereinafter. + +Besides, if the Licensor owns or comes to own one or more patents +protecting all or part of the functions of the Software or of its +components, the Licensor undertakes not to enforce the rights granted by +these patents against successive Licensees using, exploiting or +modifying the Software. If these patents are transferred, the Licensor +undertakes to have the transferees subscribe to the obligations set +forth in this paragraph. + + + 5.1 RIGHT OF USE + +The Licensee is authorized to use the Software, without any limitation +as to its fields of application, with it being hereinafter specified +that this comprises: + + 1. permanent or temporary reproduction of all or part of the Software + by any or all means and in any or all form. + + 2. loading, displaying, running, or storing the Software on any or + all medium. + + 3. entitlement to observe, study or test its operation so as to + determine the ideas and principles behind any or all constituent + elements of said Software. This shall apply when the Licensee + carries out any or all loading, displaying, running, transmission + or storage operation as regards the Software, that it is entitled + to carry out hereunder. + + + 5.2 ENTITLEMENT TO MAKE CONTRIBUTIONS + +The right to make Contributions includes the right to translate, adapt, +arrange, or make any or all modifications to the Software, and the right +to reproduce the resulting software. + +The Licensee is authorized to make any or all Contributions to the +Software provided that it includes an explicit notice that it is the +author of said Contribution and indicates the date of the creation thereof. + + + 5.3 RIGHT OF DISTRIBUTION + +In particular, the right of distribution includes the right to publish, +transmit and communicate the Software to the general public on any or +all medium, and by any or all means, and the right to market, either in +consideration of a fee, or free of charge, one or more copies of the +Software by any means. + +The Licensee is further authorized to distribute copies of the modified +or unmodified Software to third parties according to the terms and +conditions set forth hereinafter. + + + 5.3.1 DISTRIBUTION OF SOFTWARE WITHOUT MODIFICATION + +The Licensee is authorized to distribute true copies of the Software in +Source Code or Object Code form, provided that said distribution +complies with all the provisions of the Agreement and is accompanied by: + + 1. a copy of the Agreement, + + 2. a notice relating to the limitation of both the Licensor's + warranty and liability as set forth in Articles 8 and 9, + +and that, in the event that only the Object Code of the Software is +redistributed, the Licensee allows future Licensees unhindered access to +the full Source Code of the Software by indicating how to access it, it +being understood that the additional cost of acquiring the Source Code +shall not exceed the cost of transferring the data. + + + 5.3.2 DISTRIBUTION OF MODIFIED SOFTWARE + +When the Licensee makes a Contribution to the Software, the terms and +conditions for the distribution of the resulting Modified Software +become subject to all the provisions of this Agreement. + +The Licensee is authorized to distribute the Modified Software, in +source code or object code form, provided that said distribution +complies with all the provisions of the Agreement and is accompanied by: + + 1. a copy of the Agreement, + + 2. a notice relating to the limitation of both the Licensor's + warranty and liability as set forth in Articles 8 and 9, + +and that, in the event that only the object code of the Modified +Software is redistributed, the Licensee allows future Licensees +unhindered access to the full source code of the Modified Software by +indicating how to access it, it being understood that the additional +cost of acquiring the source code shall not exceed the cost of +transferring the data. + + + 5.3.3 DISTRIBUTION OF EXTERNAL MODULES + +When the Licensee has developed an External Module, the terms and +conditions of this Agreement do not apply to said External Module, that +may be distributed under a separate license agreement. + + + 5.3.4 COMPATIBILITY WITH THE GNU GPL + +The Licensee can include a code that is subject to the provisions of one +of the versions of the GNU GPL in the Modified or unmodified Software, +and distribute that entire code under the terms of the same version of +the GNU GPL. + +The Licensee can include the Modified or unmodified Software in a code +that is subject to the provisions of one of the versions of the GNU GPL, +and distribute that entire code under the terms of the same version of +the GNU GPL. + + + Article 6 - INTELLECTUAL PROPERTY + + + 6.1 OVER THE INITIAL SOFTWARE + +The Holder owns the economic rights over the Initial Software. Any or +all use of the Initial Software is subject to compliance with the terms +and conditions under which the Holder has elected to distribute its work +and no one shall be entitled to modify the terms and conditions for the +distribution of said Initial Software. + +The Holder undertakes that the Initial Software will remain ruled at +least by this Agreement, for the duration set forth in Article 4.2. + + + 6.2 OVER THE CONTRIBUTIONS + +The Licensee who develops a Contribution is the owner of the +intellectual property rights over this Contribution as defined by +applicable law. + + + 6.3 OVER THE EXTERNAL MODULES + +The Licensee who develops an External Module is the owner of the +intellectual property rights over this External Module as defined by +applicable law and is free to choose the type of agreement that shall +govern its distribution. + + + 6.4 JOINT PROVISIONS + +The Licensee expressly undertakes: + + 1. not to remove, or modify, in any manner, the intellectual property + notices attached to the Software; + + 2. to reproduce said notices, in an identical manner, in the copies + of the Software modified or not. + +The Licensee undertakes not to directly or indirectly infringe the +intellectual property rights of the Holder and/or Contributors on the +Software and to take, where applicable, vis--vis its staff, any and all +measures required to ensure respect of said intellectual property rights +of the Holder and/or Contributors. + + + Article 7 - RELATED SERVICES + +7.1 Under no circumstances shall the Agreement oblige the Licensor to +provide technical assistance or maintenance services for the Software. + +However, the Licensor is entitled to offer this type of services. The +terms and conditions of such technical assistance, and/or such +maintenance, shall be set forth in a separate instrument. Only the +Licensor offering said maintenance and/or technical assistance services +shall incur liability therefor. + +7.2 Similarly, any Licensor is entitled to offer to its licensees, under +its sole responsibility, a warranty, that shall only be binding upon +itself, for the redistribution of the Software and/or the Modified +Software, under terms and conditions that it is free to decide. Said +warranty, and the financial terms and conditions of its application, +shall be subject of a separate instrument executed between the Licensor +and the Licensee. + + + Article 8 - LIABILITY + +8.1 Subject to the provisions of Article 8.2, the Licensee shall be +entitled to claim compensation for any direct loss it may have suffered +from the Software as a result of a fault on the part of the relevant +Licensor, subject to providing evidence thereof. + +8.2 The Licensor's liability is limited to the commitments made under +this Agreement and shall not be incurred as a result of in particular: +(i) loss due the Licensee's total or partial failure to fulfill its +obligations, (ii) direct or consequential loss that is suffered by the +Licensee due to the use or performance of the Software, and (iii) more +generally, any consequential loss. In particular the Parties expressly +agree that any or all pecuniary or business loss (i.e. loss of data, +loss of profits, operating loss, loss of customers or orders, +opportunity cost, any disturbance to business activities) or any or all +legal proceedings instituted against the Licensee by a third party, +shall constitute consequential loss and shall not provide entitlement to +any or all compensation from the Licensor. + + + Article 9 - WARRANTY + +9.1 The Licensee acknowledges that the scientific and technical +state-of-the-art when the Software was distributed did not enable all +possible uses to be tested and verified, nor for the presence of +possible defects to be detected. In this respect, the Licensee's +attention has been drawn to the risks associated with loading, using, +modifying and/or developing and reproducing the Software which are +reserved for experienced users. + +The Licensee shall be responsible for verifying, by any or all means, +the suitability of the product for its requirements, its good working +order, and for ensuring that it shall not cause damage to either persons +or properties. + +9.2 The Licensor hereby represents, in good faith, that it is entitled +to grant all the rights over the Software (including in particular the +rights set forth in Article 5). + +9.3 The Licensee acknowledges that the Software is supplied "as is" by +the Licensor without any other express or tacit warranty, other than +that provided for in Article 9.2 and, in particular, without any warranty +as to its commercial value, its secured, safe, innovative or relevant +nature. + +Specifically, the Licensor does not warrant that the Software is free +from any error, that it will operate without interruption, that it will +be compatible with the Licensee's own equipment and software +configuration, nor that it will meet the Licensee's requirements. + +9.4 The Licensor does not either expressly or tacitly warrant that the +Software does not infringe any third party intellectual property right +relating to a patent, software or any other property right. Therefore, +the Licensor disclaims any and all liability towards the Licensee +arising out of any or all proceedings for infringement that may be +instituted in respect of the use, modification and redistribution of the +Software. Nevertheless, should such proceedings be instituted against +the Licensee, the Licensor shall provide it with technical and legal +assistance for its defense. Such technical and legal assistance shall be +decided on a case-by-case basis between the relevant Licensor and the +Licensee pursuant to a memorandum of understanding. The Licensor +disclaims any and all liability as regards the Licensee's use of the +name of the Software. No warranty is given as regards the existence of +prior rights over the name of the Software or as regards the existence +of a trademark. + + + Article 10 - TERMINATION + +10.1 In the event of a breach by the Licensee of its obligations +hereunder, the Licensor may automatically terminate this Agreement +thirty (30) days after notice has been sent to the Licensee and has +remained ineffective. + +10.2 A Licensee whose Agreement is terminated shall no longer be +authorized to use, modify or distribute the Software. However, any +licenses that it may have granted prior to termination of the Agreement +shall remain valid subject to their having been granted in compliance +with the terms and conditions hereof. + + + Article 11 - MISCELLANEOUS + + + 11.1 EXCUSABLE EVENTS + +Neither Party shall be liable for any or all delay, or failure to +perform the Agreement, that may be attributable to an event of force +majeure, an act of God or an outside cause, such as defective +functioning or interruptions of the electricity or telecommunications +networks, network paralysis following a virus attack, intervention by +government authorities, natural disasters, water damage, earthquakes, +fire, explosions, strikes and labor unrest, war, etc. + +11.2 Any failure by either Party, on one or more occasions, to invoke +one or more of the provisions hereof, shall under no circumstances be +interpreted as being a waiver by the interested Party of its right to +invoke said provision(s) subsequently. + +11.3 The Agreement cancels and replaces any or all previous agreements, +whether written or oral, between the Parties and having the same +purpose, and constitutes the entirety of the agreement between said +Parties concerning said purpose. No supplement or modification to the +terms and conditions hereof shall be effective as between the Parties +unless it is made in writing and signed by their duly authorized +representatives. + +11.4 In the event that one or more of the provisions hereof were to +conflict with a current or future applicable act or legislative text, +said act or legislative text shall prevail, and the Parties shall make +the necessary amendments so as to comply with said act or legislative +text. All other provisions shall remain effective. Similarly, invalidity +of a provision of the Agreement, for any reason whatsoever, shall not +cause the Agreement as a whole to be invalid. + + + 11.5 LANGUAGE + +The Agreement is drafted in both French and English and both versions +are deemed authentic. + + + Article 12 - NEW VERSIONS OF THE AGREEMENT + +12.1 Any person is authorized to duplicate and distribute copies of this +Agreement. + +12.2 So as to ensure coherence, the wording of this Agreement is +protected and may only be modified by the authors of the License, who +reserve the right to periodically publish updates or new versions of the +Agreement, each with a separate number. These subsequent versions may +address new issues encountered by Free Software. + +12.3 Any Software distributed under a given version of the Agreement may +only be subsequently distributed under the same version of the Agreement +or a subsequent version, subject to the provisions of Article 5.3.4. + + + Article 13 - GOVERNING LAW AND JURISDICTION + +13.1 The Agreement is governed by French law. The Parties agree to +endeavor to seek an amicable solution to any disagreements or disputes +that may arise during the performance of the Agreement. + +13.2 Failing an amicable solution within two (2) months as from their +occurrence, and unless emergency proceedings are necessary, the +disagreements or disputes shall be referred to the Paris Courts having +jurisdiction, by the more diligent Party. + + +Version 2.0 dated 2006-09-05. diff --git a/tools/gfx2crtc/README b/tools/gfx2crtc/README new file mode 100644 index 0000000..596349d --- /dev/null +++ b/tools/gfx2crtc/README @@ -0,0 +1,36 @@ +English Version at the end. + +Version Franaise (French Version) +---------------------------------------------------------------------- + gfx2crtc - utilitaire de convertion d'image vers image au format cpc +---------------------------------------------------------------------- + +gfx2crtc est un utilitaire qui permet la convertion d'image (format brut +lineaire 8bits par pixel ou PNG 1,2 ou 4 bits) dans un format compatible avec +l'Amstrad CPC et Plus. + +Logiciel Initial crit par : +CloudStrife/Shinra (Quentin Carlier) . +Il est diffus sur la Licence de Logiciel Libre CeCILL version 2, +Voire LICENCE pour plus d'information. +Voire le fichier AUTHORS pour voire la liste des differents Contributeur. + +Utilisation : +------------- + +English Version +---------------------------------------------------- + gfx2crtc - gfx convert tools to amstrad cpc format +---------------------------------------------------- + +gfx2crtc is a tools program for convert gfx (linear raw 8bits per pixel or +PNG 1,2 ou 4 bits) in a compatible format for Amstrad CPC and Plus. + +Initial Software write by : +CloudStrife/Shinra (Quentin Carlier) . +It is diffused on the CeCILL Free Software License v2, +See LICENSE for more information. +See AUTHORS for the list of Contributor. + +Usage : +------- \ No newline at end of file diff --git a/tools/gfx2crtc/TODO b/tools/gfx2crtc/TODO new file mode 100644 index 0000000..a394ead --- /dev/null +++ b/tools/gfx2crtc/TODO @@ -0,0 +1,9 @@ +- Ajouter un mode de convertion lineaire (quivalent R9=0) +- Extraire la palette d'un png si palette CPC +- Gestion du registre 13 // Fait r47 +- Possibilit de ne garder qu'un pixel sur 2 (exemple pour Mode 0) +- Possibilit de ne garder qu'une ligne sur 2 (exemple pour Mode 2) +- Sprite plus (4bits/pixel, 1pixel/octets, 16x16, gauche a droite, haut en bas) +- Gestion mode entrelac +- Visualisation ? +- Version Drag'n'drop pour windows ? diff --git a/tools/gfx2crtc/libraw2crtc.c b/tools/gfx2crtc/libraw2crtc.c new file mode 100644 index 0000000..b7d2f97 --- /dev/null +++ b/tools/gfx2crtc/libraw2crtc.c @@ -0,0 +1,186 @@ +/* GFX2CRTC - libraw2crtc.c + * CloudStrife - 20080921 + * Diffusé sous licence libre CeCILL v2 + * Voire LICENCE + */ + +#include +#include +#include + +unsigned short addrCalc(unsigned char vcc, unsigned char rcc, unsigned char hcc, unsigned char cclk, unsigned char r1, unsigned char r12, unsigned char r13) +{ + unsigned short MA; + unsigned short addr; + + //MA = vcc*r1 + hcc + (0x0C)*256; + MA = vcc*r1 + hcc + r12*256 + r13; + addr = cclk | ((MA & 0x03FF) << 1); + addr = addr | ((rcc & 0x07) << 11); + addr = addr | ((MA & 0x3000) << 2); + + return addr; +} + +unsigned char mode0interlace(unsigned char *x) +{ + unsigned char mode0pixel[] = {0, 64, 4, 68, 16, 80, 20, 84, 1, 65, 5, 69, 17, 81, 21, 85}; + return mode0pixel[x[0]] << 1 | mode0pixel[x[1]]; +} + +unsigned char mode1interlace(unsigned char *x) +{ + unsigned char mode1pixel[] = {0, 16, 1, 17}; + return mode1pixel[x[0]] << 3 | mode1pixel[x[1]] << 2 | mode1pixel[x[2]] << 1 | mode1pixel[x[3]]; +} + +unsigned char mode2interlace(unsigned char *x) +{ + unsigned char out = 0; + int i; + for(i = 0; i < 8; i++) out += ((x[7-i]&1) << i); + return out; +} + +unsigned char mode3interlace(unsigned char *x) +{ + unsigned char mode3pixel[] = {0, 16, 1, 17}; + return mode3pixel[x[0]] << 3 | mode3pixel[x[1]] << 2; +} + +unsigned char (*ptrMode)(unsigned char *x); + +unsigned char *raw2crtc(unsigned char *input, unsigned short width, unsigned short height, unsigned char mode, unsigned char r9, unsigned long *outSize, unsigned char *r1, unsigned char r12, unsigned char r13, unsigned char* reg6) +{ + unsigned char *outBuffer; + unsigned char *tmpBuffer; + unsigned char *allocationBuffer; + unsigned short minAddr = 0; + unsigned char minAddrIsDefined = 0; + unsigned short maxAddr; + + unsigned char nbPixPerByte; + int y,x; + + switch(mode) + { + case 0: + { + *r1 = (width+3)/4; + nbPixPerByte = 2; + ptrMode = mode0interlace; + break; + } + case 1: + { + *r1 = (width+7)/8; + nbPixPerByte = 4; + ptrMode = mode1interlace; + break; + } + case 2: + { + *r1 = (width+15)/16; + nbPixPerByte = 8; + ptrMode = mode2interlace; + break; + } + case 3: + { + *r1 = (width+3)/4; + nbPixPerByte = 2; + ptrMode = mode3interlace; + break; + } + default: + { + exit(4); + } + } + + tmpBuffer = (unsigned char*)malloc(0xFFFF); + if (tmpBuffer == NULL) + { + printf("Allocation tmpBuffer rat\n"); + exit(4); + } + + allocationBuffer = (unsigned char*)calloc(0xFFFF, 1); + if(allocationBuffer == NULL) + { + printf("Allocation allocationBuffer rat\n"); + exit(4); + } + + { + unsigned char r6; + unsigned char vcc,rcc,hcc,cclk; + r6 = (height+r9)/(r9+1); + *reg6 = r6; + + for(vcc = 0; vcc < r6; vcc++) + { + for(rcc = 0; rcc < (r9+1); rcc++) + { + for(hcc = 0; hcc < *r1; hcc++) + { + for(cclk = 0; cclk < 2; cclk++) + { + x = (hcc << 1 | cclk); + y = vcc*(r9+1) + rcc; + *(tmpBuffer + addrCalc(vcc, rcc, hcc, cclk, *r1, r12, r13)) = (*ptrMode)(input + y*width + x*nbPixPerByte); + *(allocationBuffer + addrCalc(vcc, rcc, hcc, cclk, *r1, r12, r13)) += 1; + } + } + } + } + } + + { + unsigned short i; + for(i = 0; i < 0xFFFF; i++) + { + if(*(allocationBuffer + i) > 1) + { + printf("Attention : Ecriture multiple a l'adresse mmoire %d\n",i); + } + if(*(allocationBuffer + i) > 0) + { + maxAddr = i; + } + if((*(allocationBuffer + i) == 1) && (minAddrIsDefined == 0)) + { + minAddr = i; + minAddrIsDefined = 1; + } + } + } + + *outSize = (maxAddr + 1) - minAddr; + + outBuffer = (unsigned char*)malloc((*outSize)); + if (outBuffer == NULL) + { + printf("Allocation outBuffer rat\n"); + exit(4); + } + + { + unsigned char *ptrTmp; + unsigned char *ptrOut; + unsigned short i; + ptrTmp = tmpBuffer + minAddr; + ptrOut = outBuffer; + + for(i = minAddr; i <= maxAddr; i++) + { + *(ptrOut++) = *(ptrTmp++); + } + } + free(tmpBuffer); + tmpBuffer = NULL; + free(allocationBuffer); + allocationBuffer = NULL; + + return outBuffer; +} diff --git a/tools/gfx2crtc/libraw2crtc.h b/tools/gfx2crtc/libraw2crtc.h new file mode 100644 index 0000000..8bab0e5 --- /dev/null +++ b/tools/gfx2crtc/libraw2crtc.h @@ -0,0 +1,12 @@ +/* GFX2CRTC - libraw2crtc.h + * CloudStrife - 20080921 + * Diffus sous licence libre CeCILL v2 + * Voire LICENCE + */ + +#ifndef LIBRAW2CRTC_H +#define LIBRAW2CRTC_H 1 + +unsigned char * raw2crtc(unsigned char *input, unsigned short width, unsigned short height, unsigned char mode, unsigned char r9, unsigned long *outSize, unsigned char *r1, unsigned char r12, unsigned char r13, unsigned char* reg6); + +#endif diff --git a/tools/gfx2crtc/makefile b/tools/gfx2crtc/makefile new file mode 100644 index 0000000..8e4b2e2 --- /dev/null +++ b/tools/gfx2crtc/makefile @@ -0,0 +1,29 @@ +ALL= raw2crtc png2crtc + + +CC=gcc + +# Detect gcc2, if we're running it, use gnu9x standard instead of c99... +GCC_MAJOR = $(shell $(CC) -v 2>&1 |grep version |cut -d' ' -f3 |cut -d'.' -f1) + +ifeq ($(GCC_MAJOR),2) + CCFLAGS=-Os -W -Wall -std=gnu9x -g +else + CCFLAGS=-Os -W -Wall -std=c99 -g +endif + +#CCFLAGS=-O3 -W -Wall -pedantic -ansi + +all: $(ALL) + +clean : + rm -f a.out *.o core $(ALL) + +raw2crtc : raw2crtc.o libraw2crtc.o + $(CC) $(CCFLAGS) raw2crtc.o libraw2crtc.o -o raw2crtc + +png2crtc : png2crtc.o libraw2crtc.o + $(CC) $(CCFLAGS) png2crtc.o libraw2crtc.o -o png2crtc -lpng -lz + +.c.o : + $(CC) $(CCFLAGS) -c $< diff --git a/tools/gfx2crtc/png2crtc.c b/tools/gfx2crtc/png2crtc.c new file mode 100644 index 0000000..9742960 --- /dev/null +++ b/tools/gfx2crtc/png2crtc.c @@ -0,0 +1,204 @@ +/* GFX2CRTC - png2crtc.c + * CloudStrife - 20080921 + * Diffusé sous licence libre CeCILL v2 + * Voire LICENCE + */ + +#include +#include +#include +#include "libraw2crtc.h" + +#define ERROR 1 + +int main(int argc, char **argv) +{ + FILE *inFile, *outFile; + unsigned char *inBuffer, *outBuffer; + unsigned long outSize; + + unsigned char r1, r6, r9, r12, r13; + png_uint_32 width; + png_uint_32 height; + int bitdepth; + int colorType; + unsigned char mode; + unsigned char forcemode = 0; + unsigned char forcer12 = 0, forcer13 = 0; + + unsigned char header[8]; + unsigned char is_png; + + unsigned int y; + png_structp png_ptr; + png_infop info_ptr; + png_infop end_info; + + png_bytep * ptrRow; + + // We have to use this temporary variable insted of scanning directly into + // 8 bit integers using %hhu because mingW, relying on MSVCRT, is not C99 + // compliant and can't handle this "modern" stuff. + unsigned int stupid_mingw_isnt_c99; + + if((argc != 3) && (argc != 4) && (argc != 5) && (argc != 6) && (argc != 7)) + { + printf("Utilisation : %s input_filename output_filename [registre9] [mode] " + "[r12] [r13]\n",argv[0]); + exit(0); + } + + inFile = fopen(argv[1],"rb"); + + if(argc >= 4) + /*{sscanf(argv[3],"%hhu",&r9);}*/ + {sscanf(argv[3],"%u",&stupid_mingw_isnt_c99); r9=stupid_mingw_isnt_c99;} + else + {r9 = 7;} + if(argc >= 5) + { + // sscanf(argv[4],"%hhu",&mode); + sscanf(argv[4],"%u",&stupid_mingw_isnt_c99); mode = stupid_mingw_isnt_c99; + forcemode = 1; + if(mode > 3) puts("mode doit tre compris entre 0 et 3"); + mode = mode & 3; + } + + // Registre r12 et r13 par dfaut : + r12 = 0x0C; + r13 = 0x00; + + if(argc >= 6) + { + // sscanf(argv[5],"%hhu",&r12); + sscanf(argv[5],"%u",&stupid_mingw_isnt_c99); r12 = stupid_mingw_isnt_c99; + forcer12 = 1; + } + if(argc >= 7) + { + // sscanf(argv[6],"%hhu",&r13); + sscanf(argv[6],"%u",&stupid_mingw_isnt_c99); r13=stupid_mingw_isnt_c99; + forcer13 = 1; + } + + if (inFile == NULL) + { + printf("Fichier Inexistant\n"); + exit(1); + } + + fread(header, 1, 8, inFile); + is_png = !png_sig_cmp(header, 0, 8); + if (!is_png) + { + printf("Ce n'est pas un png\n"); + exit(2); + } + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, + NULL); + if (!png_ptr) return (ERROR); + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + return (ERROR); + } + + end_info = png_create_info_struct(png_ptr); + if (!end_info) + { + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + return (ERROR); + } + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + fclose(inFile); + return (ERROR); + } + + png_init_io(png_ptr, inFile); + png_set_sig_bytes(png_ptr, 8); + + png_read_info(png_ptr, info_ptr); + + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bitdepth, &colorType, NULL, + NULL, NULL); + + if(!((colorType == PNG_COLOR_TYPE_GRAY) + || (colorType == PNG_COLOR_TYPE_PALETTE))) + { + puts("Ce PNG n'est pas dans un format exploitable " + "(niveaux de gris ou palette)"); + return (ERROR); + } + + if(forcemode == 0) + { + switch(bitdepth) + { + case 1: + { + mode = 2; + break; + } + case 2: + { + mode = 1; + break; + } + case 4: + { + mode = 0; + break; + } + default: + { + puts("Ce PNG n'est pas dans un format exploitable" + "(bitdepth = 1, 2 ou 4)"); + return (ERROR); + } + } + } + + png_set_packing(png_ptr); /* Convertir en mode 1 pixel par octets */ + png_read_update_info(png_ptr, info_ptr); + + inBuffer = (unsigned char*)malloc(width*height); + if (inBuffer == NULL) + { + printf("Allocation inBuffer rat\n"); + exit(3); + } + + ptrRow = (png_bytep*)malloc(sizeof(png_bytep)*height); + for(y = 0; y < height; y++) + { + ptrRow[y] = (inBuffer + width*y); + } + + png_read_image(png_ptr, ptrRow); + + outBuffer = raw2crtc(inBuffer, width, height, mode, r9, &outSize, &r1, r12, r13, &r6); + + printf("Taille de l'cran de sortie : %lu\n",outSize); + printf("Mode = %d Largeur = %d Hauteur = %d R1 = %d R9 = %d R6 = %d\n",mode,(int)width,(int)height,r1,r9,r6); + + outFile = fopen(argv[2], "wb"); + fwrite(outBuffer, 1, outSize, outFile); + fclose(outFile); + + png_read_end(png_ptr, end_info); + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + + free(inBuffer); + inBuffer = NULL; + + free(outBuffer); + outBuffer = NULL; + + return 0; +} diff --git a/tools/gfx2crtc/raw2crtc.c b/tools/gfx2crtc/raw2crtc.c new file mode 100644 index 0000000..c8738dc --- /dev/null +++ b/tools/gfx2crtc/raw2crtc.c @@ -0,0 +1,86 @@ +/* GFX2CRTC - raw2crtc.c + * CloudStrife - 20080921 + * Diffusé sous licence libre CeCILL v2 + * Voire LICENCE + */ + +#include +#include +#include "libraw2crtc.h" + +int main(int argc, char **argv) +{ + FILE *inFile, *outFile; + unsigned char *inBuffer, *outBuffer; + unsigned long inSize; + unsigned long outSize; + + unsigned char r1, r6, r9; + unsigned short width; + unsigned short height; + unsigned char mode; + + if((argc != 6) && (argc != 7)) + { + printf("Utilisation : %s input_filename output_filename width height mode [registre9]\n",argv[0]); + printf("Exemple : Convertir une image en 176 sur 224 en mode 0 :\n"); + printf("%s image.raw image.scr 176 224 0\n",argv[0]); + printf("Exemple : Convertir une image en 256 sur 128 en mode 1 avec R9 = 3 :\n"); + printf("%s image.raw image.scr 256 128 1 3\n",argv[0]); + exit(0); + } + + inFile = fopen(argv[1],"rb"); + + sscanf(argv[3],"%hud",&width); + sscanf(argv[4],"%hud",&height); + sscanf(argv[5],"%hhud",&mode); + if(mode > 3) printf("mode doit tre compris entre 0 et 3"); + mode = mode & 3; + if(argc == 7) + {sscanf(argv[6],"%hhud",&r9);} + else + {r9 = 7;} + + if (inFile == NULL) + { + printf("Fichier Inexistant\n"); + exit(1); + } + + fseek(inFile, 0, SEEK_END); + inSize = ftell(inFile); + rewind(inFile); + + if (inSize != (unsigned long)(width*height)) + { + printf("Attention ! Mauvaise taille du fichier d'entr\n"); + } + + inBuffer = (unsigned char*)malloc(inSize); + if (inBuffer == NULL) + { + printf("Allocation inBuffer rat\n"); + exit(3); + } + + fread(inBuffer, 1, inSize, inFile); + fclose(inFile); + + outBuffer = raw2crtc(inBuffer, width, height, mode, r9, &outSize, &r1, 0, 0, &r6); + + printf("Taille de l'cran de sortie : %lu\n",outSize); + printf("Mode = %d Largeur = %d Hauteur = %d R1 = %d R9 = %d R6 = %d\n",mode,width,height,r1,r9,r6); + + outFile = fopen(argv[2], "wb"); + fwrite(outBuffer, 1, outSize, outFile); + fclose(outFile); + + free(inBuffer); + inBuffer = NULL; + + free(outBuffer); + outBuffer = NULL; + + return 0; +} diff --git a/tools/hex2bin-2.0/Makefile b/tools/hex2bin-2.0/Makefile new file mode 100755 index 0000000..c8ef10b --- /dev/null +++ b/tools/hex2bin-2.0/Makefile @@ -0,0 +1,42 @@ +# Makefile hex2bin/mot2bin +SRCDIR = src +BINDIR = bin +OBJDIR = obj +TGTDIR = $(BINDIR) +B_SRCFILES= $(foreach F, hex2bin.c common.c libcrc.c binary.c, $(SRCDIR)/$(F)) +B_OBJFILES= $(foreach F, hex2bin.o common.o libcrc.o binary.o, $(OBJDIR)/$(F)) +M_SRCFILES= $(foreach F, mot2bin.c common.c libcrc.c binary.c, $(SRCDIR)/$(F)) +M_OBJFILES= $(foreach F, mot2bin.o common.o libcrc.o binary.o, $(OBJDIR)/$(F)) + +# For generating documentation (hex2bin.1, select the second line) +# -- You will require pod2man installed for this to work +TGT_FILES = $(foreach F, hex2bin mot2bin, $(TGTDIR)/$(F)) +#TGT_FILES = $(foreach F, hex2bin mot2bin hex2bin.1, $(TGTDIR)/$(F)) + +CPFLAGS = -std=gnu99 -O3 -fsigned-char -Wall -pedantic +# Compile +all: objectdir $(TGT_FILES) + +$(OBJDIR)/%.o: $(SRCDIR)/%.c + gcc -c $(CPFLAGS) $< -o $@ + +objectdir: + @echo "Creating directory $(OBJDIR)..." + mkdir -p $(OBJDIR) + +$(TGTDIR)/hex2bin.1: $(SRCDIR)/hex2bin.pod + pod2man $(SRCDIR)/hex2bin.pod > $(TGTDIR)/hex2bin.1 + +$(TGTDIR)/hex2bin: $(B_OBJFILES) + gcc $(CPFLAGS) -o $(TGTDIR)/hex2bin $(B_OBJFILES) + +$(TGTDIR)/mot2bin: $(M_OBJFILES) + gcc $(CPFLAGS) -o $(TGTDIR)/mot2bin $(M_OBJFILES) + +clean: + @echo "Removing objects directory $(OBJDIR)/ ..." + @rm -rf $(OBJDIR) + +cleanall: clean + @echo "Removing binary files in $(BINDIR)/ ..." + @rm -f $(BINDIR)/* diff --git a/tools/hex2bin-2.0/bin/.deleteme b/tools/hex2bin-2.0/bin/.deleteme new file mode 100644 index 0000000..e69de29 diff --git a/tools/hex2bin-2.0/bin/hex2bin b/tools/hex2bin-2.0/bin/hex2bin new file mode 100755 index 0000000..c6967d7 Binary files /dev/null and b/tools/hex2bin-2.0/bin/hex2bin differ diff --git a/tools/hex2bin-2.0/bin/mot2bin b/tools/hex2bin-2.0/bin/mot2bin new file mode 100755 index 0000000..18400f4 Binary files /dev/null and b/tools/hex2bin-2.0/bin/mot2bin differ diff --git a/tools/hex2bin-2.0/doc/CRC list.txt b/tools/hex2bin-2.0/doc/CRC list.txt new file mode 100644 index 0000000..8549799 --- /dev/null +++ b/tools/hex2bin-2.0/doc/CRC list.txt @@ -0,0 +1,542 @@ +http://regregex.bbcmicro.net/crc-catalogue.htm + +CRC-8 +07 + + Name : "CRC-8" + Width : 8 + Poly : 07 + Init : 00 + RefIn : False + RefOut : False + XorOut : 00 + Check : F4 + + + Name : "CRC-8/ITU" + Width : 8 + Poly : 07 + Init : 00 + RefIn : False + RefOut : False + XorOut : 55 + Check : A1 + + + Name : "CRC-8/ROHC" + Width : 8 + Poly : 07 + Init : FF + RefIn : True + RefOut : True + XorOut : 0 + Check : D0 + +39 + + Name : "CRC-8/DARC" + Width : 8 + Poly : 39 + Init : 00 + RefIn : True + RefOut : True + XorOut : 00 + Check : 15 + +1D + + Name : "CRC-8/I-CODE" + Width : 8 + Poly : 1D + Init : FD + RefIn : False + RefOut : False + XorOut : 00 + Check : 7E + + + Name : "CRC-8/J1850" (new entry) + Width : 8 + Poly : 1D + Init : FF + RefIn : False + RefOut : False + XorOut : FF + Check : 4B + +31 + + Name : "CRC-8/MAXIM" + Alias : "DOW-CRC" + Width : 8 + Poly : 31 + Init : 00 + RefIn : True + RefOut : True + XorOut : 00 + Check : A1 + +9B + + Name : "CRC-8/WCDMA" + Width : 8 + Poly : 9B + Init : 00 + RefIn : True + RefOut : True + XorOut : 00 + Check : 25 + +8D + + Name : "CRC-8/CCITT" (new entry) 1-Wire? + Width : 8 + Poly : 8D + Init : 00? + RefIn : False? + RefOut : False? + XorOut : 00? + Check : D2 + +D5 + + Name : "CRC-8" (new entry) + Width : 8 + Poly : D5 + Init : 00? + RefIn : False? + RefOut : False? + XorOut : 00? + Check : BC + +CRC-16 +8005 + + Name : "ARC" + Alias : "CRC-16" + Alias : "CRC-IBM" + Alias : "CRC-16/ARC" + Alias : "CRC-16/LHA" + Width : 16 + Poly : 8005 + Init : 0000 + RefIn : True + RefOut : True + XorOut : 0000 + Check : BB3D + + + Name : "CRC-16/BUYPASS" + Alias : "CRC-16/VERIFONE" + Width : 16 + Poly : 8005 + Init : 0000 + RefIn : False + RefOut : False + XorOut : 0000 + Check : FEE8 + + + Name : "CRC-16/DDS-110" + Width : 16 + Poly : 8005 + Init : 800D + RefIn : False + RefOut : False + XorOut : 0000 + Check : 9ECF + XCheck : CFE9 + + + Name : "CRC-16/MAXIM" + Width : 16 + Poly : 8005 + Init : 0000 + RefIn : True + RefOut : True + XorOut : FFFF + Check : 44C2 + + + Name : "CRC-16/USB" + Width : 16 + Poly : 8005 + Init : FFFF + RefIn : True + RefOut : True + XorOut : FFFF + Check : B4C8 + + + Name : "MODBUS" + Width : 16 + Poly : 8005 + Init : FFFF + RefIn : True + RefOut : True + XorOut : 0000 + Check : 4B37 + +1021 + + Name : "CRC-16/AUG-CCITT" + Alias : "CRC-16/SPI-FUJITSU" + Width : 16 + Poly : 1021 + Init : 1D0F + RefIn : False + RefOut : False + XorOut : 0000 + Check : E5CC + + + Name : "CRC-16/CCITT-FALSE" + Width : 16 + Poly : 1021 + Init : FFFF + RefIn : False + RefOut : False + XorOut : 0000 + Check : 29B1 + + + Name : "CRC-16/GENIBUS" + Alias : "CRC-16/I-CODE" + Alias : "CRC-16/DARC" + Width : 16 + Poly : 1021 + Init : FFFF + RefIn : False + RefOut : False + XorOut : FFFF + Check : D64E + + + Name : "XMODEM" + Alias : "ZMODEM" + Alias : "CRC-16/ACORN" + Width : 16 + Poly : 1021 + Init : 0000 + RefIn : False + RefOut : False + XorOut : 0000 + Check : 31C3 + + + Name : "CRC-16/MCRF4XX" + Width : 16 + Poly : 1021 + Init : FFFF + RefIn : True + RefOut : True + XorOut : 0000 + Check : 6F91 + + + Name : "CRC-16/RIELLO" + Width : 16 + Poly : 1021 + Init : B2AA + RefIn : True + RefOut : True + XorOut : 0000 + Check : 63D0 + + + Name : "KERMIT" + Alias : "CRC-16/CCITT" + Alias : "CRC-16/CCITT-TRUE" + Alias : "CRC-CCITT" + Width : 16 + Poly : 1021 + Init : 0000 + RefIn : True + RefOut : True + XorOut : 0000 + Check : 2189 + XCheck : 8921 + + + Name : "X-25" + Alias : "CRC-16/IBM-SDLC" + Alias : "CRC-16/ISO-HDLC" + Width : 16 + Poly : 1021 + Init : FFFF + RefIn : True + RefOut : True + XorOut : FFFF + Check : 906E + XCheck : 6E90 + +0589 + + Name : "CRC-16/DECT-R" + Alias : "R-CRC-16" + Width : 16 + Poly : 0589 + Init : 0000 + RefIn : False + RefOut : False + XorOut : 0001 + Check : 007E + + + Name : "CRC-16/DECT-X" + Alias : "X-CRC-16" + Width : 16 + Poly : 0589 + Init : 0000 + RefIn : False + RefOut : False + XorOut : 0000 + Check : 007F + +3D65 + + Name : "CRC-16/DNP" + Width : 16 + Poly : 3D65 + Init : 0000 + RefIn : True + RefOut : True + XorOut : FFFF + Check : EA82 + XCheck : 82EA + + + Name : "CRC-16/EN-13757" + Width : 16 + Poly : 3D65 + Init : 0000 + RefIn : False + RefOut : False + XorOut : FFFF + Check : C2B7 + +8BB7 + + Name : "CRC-16/T10-DIF" + Width : 16 + Poly : 8BB7 + Init : 0000 + RefIn : False + RefOut : False + XorOut : 0000 + Check : D0DB + +A097 + + Name : "CRC-16/TELEDISK" + Width : 16 + Poly : A097 + Init : 0000 + RefIn : False + RefOut : False + XorOut : 0000 + Check : 0FB3 + +CRC-24 +864CFB + + Name : "CRC-24" + Alias : "CRC-24/OPENPGP" + Width : 24 + Poly : 864CFB + Init : B704CE + RefIn : False + RefOut : False + XorOut : 000000 + Check : 21CF02 + +5D6DCB + + Name : "CRC-24/FLEXRAY-A" + Width : 24 + Poly : 5D6DCB + Init : FEDCBA + RefIn : False + RefOut : False + XorOut : 000000 + Check : 7979BD + + + Name : "CRC-24/FLEXRAY-B" + Width : 24 + Poly : 5D6DCB + Init : ABCDEF + RefIn : False + RefOut : False + XorOut : 000000 + Check : 1F23B8 + +CRC-32 +04C11DB7 + + Name : "CRC-32" + Alias : "CRC-32/ADCCP" + Alias : "PKZIP" + Width : 32 + Poly : 04C11DB7 + Init : FFFFFFFF + RefIn : True + RefOut : True + XorOut : FFFFFFFF + Check : CBF43926 + + + Name : "CRC-32/BZIP2" + Alias : "B-CRC-32" + Width : 32 + Poly : 04C11DB7 + Init : FFFFFFFF + RefIn : False + RefOut : False + XorOut : FFFFFFFF + Check : FC891918 + + + Name : "CRC-32/MPEG-2" + Width : 32 + Poly : 04C11DB7 + Init : FFFFFFFF + RefIn : False + RefOut : False + XorOut : 00000000 + Check : 0376E6E7 + + + Name : "CRC-32/POSIX" + Alias : "CKSUM" + Width : 32 + Poly : 04C11DB7 + Init : 00000000 + RefIn : False + RefOut : False + XorOut : FFFFFFFF + Check : 765E7680 + LCheck : 377A6011 + + + Name : "JAMCRC" + Width : 32 + Poly : 04C11DB7 + Init : FFFFFFFF + RefIn : True + RefOut : True + XorOut : 00000000 + Check : 340BC6D9 + +1EDC6F41 + + Name : "CRC-32C" + Alias : "CRC-32/ISCSI" + Alias : "CRC-32/CASTAGNOLI" + Width : 32 + Poly : 1EDC6F41 + Init : FFFFFFFF + RefIn : True + RefOut : True + XorOut : FFFFFFFF + Check : E3069283 + +A833982B + + Name : "CRC-32D" + Width : 32 + Poly : A833982B + Init : FFFFFFFF + RefIn : True + RefOut : True + XorOut : FFFFFFFF + Check : 87315576 + +741B8CD7 + (new entry) + Name : "CRC-32K" + Alias : "CRC-32/KOOPMAN" + Width : 32 + Poly : 741B8CD7 + Init : 00000000? + RefIn : False? + RefOut : False? + XorOut : 00000000? + Check : 085A3197 ? + +814141AB + + Name : "CRC-32Q" + Width : 32 + Poly : 814141AB + Init : 00000000 + RefIn : False + RefOut : False + XorOut : 00000000 + Check : 3010BF7F + +000000AF + + Name : "XFER" + Width : 32 + Poly : 000000AF + Init : 00000000 + RefIn : False + RefOut : False + XorOut : 00000000 + Check : BD0BE338 + +CRC-40 + + Name : "CRC-40/GSM" + Width : 40 + Poly : 0004820009 + Init : 0000000000 + RefIn : False + RefOut : False + XorOut : 0000000000 + Check : 2BE9B039B9 + +CRC-64 +42F0E1EBA9EA3693 + + Name : "CRC-64" + Width : 64 + Poly : 42F0E1EBA9EA3693 + Init : 0000000000000000 + RefIn : False + RefOut : False + XorOut : 0000000000000000 + Check : 6C40DF5F0B497347 + + + Name : "CRC-64/WE" + Width : 64 + Poly : 42F0E1EBA9EA3693 + Init : FFFFFFFFFFFFFFFF + RefIn : False + RefOut : False + XorOut : FFFFFFFFFFFFFFFF + Check : 62EC59E3F1A4F00A + +000000000000001B + + Name : "CRC-64/1B" (New entry) + Width : 64 + Poly : 000000000000001B + Init : 0000000000000000 + RefIn : True + RefOut : True + XorOut : 0000000000000000 + Check : 46A5A9388A5BEFFE + +AD93D23594C935A9 + + Name : "CRC-64/Jones" (New entry) + Width : 64 + Poly : AD93D23594C935A9 + Init : FFFFFFFFFFFFFFFF + RefIn : True + RefOut : True + XorOut : 0000000000000000 + Check : CAA717168609F281 diff --git a/tools/hex2bin-2.0/doc/ChangeLog_hex2bin b/tools/hex2bin-2.0/doc/ChangeLog_hex2bin new file mode 100644 index 0000000..3339250 --- /dev/null +++ b/tools/hex2bin-2.0/doc/ChangeLog_hex2bin @@ -0,0 +1,57 @@ +(UTF8 encoding) + +- hex2bin 1.0.12 - 20141122 Simone Fratini + small feature added + 20141121 Slucx + added line for removing extra CR when entering file name at run time. + 20141008 JP + removed junk code + +- hex2bin 1.0.11 - 20141005 Jacques Pelletier + added option to support byte-swapped hex used by Microchip's MPLAB IDE + corrected bug caused by extra LF at end or within file + +- hex2bin 1.0.10 - 20120509 Yoshimasa Nakane + modified error checking (also for output file, JP) + modified option parser (JP) + +- hex2bin 1.0.9 - 20120125 - Danny Schneider + Added code for filling a binary file to a given Max_Length relative to + Starting Address if Max-Address is larger than Highest-Address + +- hex2bin 1.0.8 - 20100402 - Jacques Pelletier + Fixed a bug with physical address calculation with extended linear address records + ADDRESS_MASK is now calculated from MEMORY_SIZE + +- hex2bin 1.0.7 - 20091212 - Jacques Pelletier + Fixed the crash on 0 byte length data records + +- hex2bin 1.0.6 - 20080103 - Jacques Pelletier + Fixed a bug when generating binary files near the end of the buffer + +- hex2bin 1.0.5 - 20071005 - Paweł Grabski - + Improved parsing of options. + +- hex2bin 1.0.4 - 20050126 - Jacques Pelletier - + Corrected the conversion LF -> CR+LF bug + applied patch for correcting the incorrect handling of + extended segment address record + added the Rockwell checksum extensions, and modified them a bit to allow + other types later. + +- hex2bin 1.0.3 - 20040617 - Alf Lacis - + Added pad byte (may not always want FF). + Added 'break;' to remove GNU compiler warning about label at + end of compound statement + Added PROGRAM & VERSION strings. + +- hex2bin 1.0.2 - + Corrected Bug in checksum verification + +- hex2bin 1.0.1 - + Added checking for memory indexing out of bound. + Added segmented and linear extended addressing in hex2bin. + Corrected an error: & were interverted with && (and bitwise, logical and). + +- hex2bin 1.0.0 - + Initial release diff --git a/tools/hex2bin-2.0/doc/ChangeLog_mot2bin b/tools/hex2bin-2.0/doc/ChangeLog_mot2bin new file mode 100644 index 0000000..4e3c7b3 --- /dev/null +++ b/tools/hex2bin-2.0/doc/ChangeLog_mot2bin @@ -0,0 +1,49 @@ +(UTF8 encoding tab = 4) +- mot2bin 1.0.12 - 20141122 Simone Fratini + small feature added + 20141121 Slucx + added line for removing extra CR when entering file name at run time. + +- mot2bin 1.0.11 - 20141005 Jacques Pelletier + added option to support byte-swapped hex used by Microchip's MPLAB IDE + corrected bug caused by extra LF at end or within file + +- mot2bin 1.0.10 - 20120509 Yoshimasa Nakane + modified error checking (also for output file, JP) + +- mot2bin 1.0.9 - 20120125 - Danny Schneider + Added code for filling a binary file to a given Max_Length relative to + Starting Address if Max-Address is larger than Highest-Address + (JP) corrected a bug in the checksum checking + (JP) added code for record types 0,5,7,8,9 + +- mot2bin 1.0.8 - 20100402 - Jacques Pelletier + ADDRESS_MASK is now calculated from MEMORY_SIZE + +- mot2bin 1.0.7 - 20091212 - Jacques Pelletier + Fixed the crash on 0 byte length data records + +- mot2bin 1.0.6 - 20080103 - Jacques Pelletier + Corrected a bug when generating a binary file near the end of the buffer. + +- mot2bin 1.0.5 - 20071005 - Paweł Grabski - + Improved parsing of options (same code as hex2bin). + +- mot2bin 1.0.4 - 20050128 - Jacques Pelletier - + Modified the checksum code to be able to generate other checksum types + later (ex. CRC). + +- mot2bin 1.0.3 - 20041026 - Scott A. Mintz - + Modified the MOT2BIN file to compute a checksum over a range using + 8bit, 16bit little endian, or 16bit big endian and optionally forcing + the checksum to a specific value by modifying a memory location. + +- mot2bin 1.0.2 - 20040617 - Alf Lacis - + Added pad byte (may not always want FF). + Added initialisation to Checksum to remove GNU + compiler warning about possible uninitialised usage + Added 2x'break;' to remove GNU compiler warning about label at + end of compound statement + Added PROGRAM & VERSION strings. + +- no previous ChangeLog - diff --git a/tools/hex2bin-2.0/doc/README b/tools/hex2bin-2.0/doc/README new file mode 100644 index 0000000..78ee7e7 --- /dev/null +++ b/tools/hex2bin-2.0/doc/README @@ -0,0 +1,225 @@ +Yet Another Hex to bin converter + +It can handle the extended Intel hex format in segmented and linear address +modes. Records need not be sorted and there can be gaps between records. + +Some hex files are produced by compilers. They generate objects files for each +module in a project, and when the linker generates the final hex file, the +object files are stored within the hex files, but modules can appear not +necessary in order of address. + +How does it work? + +Hex2bin/mot2bin allocates a 4 MBytes buffer and just place the converted bytes +in its buffer. At the end, the buffer is written to disk. Using a buffer elimi- +nates the need to sort records. If the option l is used (3), the buffer will be +allocated with the maximum size specified if over 4Mbytes. + +Before reading the hex file, the buffer is filled with a default value. These +padding bytes are all FF by default so an EPROM programmer can skip these bytes +when programming. The padding value can be changed with the -p option. + +1. Compiling on Linux or other unix platforms + + make + + then + + make install + + This will install the program to /usr/local/bin. + +1a. Compiling for Windows on Msys, Cygwin or DOS prompt + + The programs can be compiled as follows: + gcc -O2 -Wall -o hex2bin.exe hex2bin.c common.c libcrc.c binary.c + gcc -O2 -Wall -o mot2bin.exe mot2bin.c common.c libcrc.c binary.c + +2. Using hex2bin + + hex2bin example.hex + + hex2bin will generate a binary file example.bin starting at the + lowest address in the hex file. + +3. Binary file starting address and length + + If the lowest address isn't 0000, + ex: 0100: (the first record begins with :nn010000xxx ) + + there will be problems when using the binary file to program a EPROM + since the first byte supposed to be at 0100 is stored in the binary file + at 0000. + + you can specify a starting address for the binary file on the command line: + + hex2bin -s 0000 start_at_0100.hex + + This start address is not the same thing as the start address record in + the hex file. The start address record is used to specify the starting + address for execution of the binary code. + + The bytes will be stored in the binary file with a padding from 0000 + to the lowest address minus 1 (00FF in this case). + + Similarly, the binary file can be padded up to Length -1 with FF or another byte. + + Here, the space between the last byte and 07FF will be filled with FF. + hex2bin -l 0800 ends_before_07FF.hex + + EPROM, EEPROM and Flash memories contain all FF when erased. + + This program does minimal error checking since many hex files are + generated by known good assemblers. + + When the source file name is + for-example.test.hex + the binary created will have the name + for-example.bin + the ".test" part will be dropped. + + Hex2bin/mot2bin assume the source file doesn't contain overlapping records, + if so, overlaps will be reported. + +4. Checksum of source file + + By default, it ignores record checksum errors, so that someone can change + by hand some bytes allowing quick and dirty changes. + If you want checksum error reporting, specify the option -c. + + hex2bin -c example.hex + + If there is a record checksum error somewhere, the program will continue the + conversion anyway. + + The example file example.hex contains some records with checksum errors. + +5. Check value inserted inside binary file + + A check value can be inserted in the resulting binary file. + + hex2bin -k [0-4] -r [start] [end] -f [address] -C [Poly] [Init] [RefIn] [RefOut] [XorOut] + + -k Select the check method: + 0: Checksum 8-bit + 1: Checksum 16-bit + 2: CRC8 + 3: CRC16 + 4: CRC32 + + -r Range to compute checksum over (default is min and max addresses) + + -f Address of the result to write + + -C Parameters for CRC + Parameters for common CRCs are listed in doc/CRC list.txt. They appear in + the same order. Feed them as is and use t for TRUE, f for FALSE. + + See also the test/Makefile for these common CRCs; since they're tested, + you'll have the command line figured out. + + -E Endian for storing the check result or forcing it + 0: little + 1: big + + Change from previous versions of hex2bin/mot2bin: + Replace former options to this version + -k 1 -> -k 1 -E 0 + -k 2 -> -k 1 -E 1 + +6. Value inserted directly inside binary file + Instead of calculating a value, it can be inserted directly into the file at a specified address. + + hex2bin -k [0|1|2] -F [address] [value] + + -k Select the value format: + + 0 = 8-bit + 1 = 16-bit + 2 = 32-bit + + -F Address and value of checksum to force + + -E Endian for storing the check result or forcing it + 0: little + 1: big + +7. Motorola S files + + mot2bin example.s19 + + Options for mot2bin are the same as hex2bin. Executing the program + without argument will display available options. Some are specific to + Motorola files. + + This program will handle S19 files generated for Motorola micropro- + cessors. Since I use this program for an EPROM programmer, I will + rarely need to have more than 4M, I limited the source program for + 24 bits or 16 bits address records. + + 32 bits records are now supported, but obviously I can't allocate all + the memory for the binary target. What I did is simply assume that the + binary file will occupy less than 4M. For binary files greater than 4M, + see length option (section 3). + +8. Support for byte-swapped hex/S19 files + + -w Wordwise swap: for each pair of bytes, exchange the low and high part. + If a checksum needs to be generated to insert in the binary file, select + one of the 16-bit checksums. + + hex2bin -w test-byte-swap.hex + +9. Goodies + + Description of the file formats is included. + Added examples files for extended addressing. + + Check for overlapping records. The check is rather basic: supposing + that the buffer is filled with pad bytes, when a record overlaps a + previous one, value in the buffer will be different from the pad bytes. + This will not detect the case when the previous value equals the pad byte, + but it's more likely that more than one byte will be overlapped. + + +10. Error messages + + "Can't allocate memory." + + Can't do anything in this case, so the program simply exits. + + "Error occurred while reading from file" + + Problem with fgets. + + "Input/Output file %s cannot be opened. Enter new filename: " + + The user may not have permissions to open the file. + + "0 byte length data record ignored" + + This means that an empty data record was read. Since it's empty, it's simply + ignored and should have no impact on the binary file. + + "Data record skipped at ..." + + This means that the records are falling outside the memory buffer. + + "Overlapped record detected" + + A record is overwritten by a subsequent record. If you're using SDCC, check + if more than one area is specified with a starting address. Checking the map + file generated by the linker can help. + + "Some error occurred when parsing options." + + + +11. History + + See ChangeLog + +12. Other hex tool + + There is a program that supports more formats and has more features. + See SRecord at http://srecord.sourceforge.net/ diff --git a/tools/hex2bin-2.0/doc/S-record.txt b/tools/hex2bin-2.0/doc/S-record.txt new file mode 100644 index 0000000..ba4abc1 --- /dev/null +++ b/tools/hex2bin-2.0/doc/S-record.txt @@ -0,0 +1,361 @@ +S-Record Format + + A file in Motorola S-record format is an ASCII file. There are three different + formats: + + S19 for 16-bit address + S2 for 24-bit address + S3 for 32-bit address + + + The files consist of optional symbol table information, data specifications + for loading memory, and a terminator record. + + [ $$ {module_record} + symbol records + $$ [ module_record ] + symbol_records + $$] + header_record + data_records + record_count_record + terminator_record + + +Module Record (Optional) + + Each object file contains one record for each module that is a component of it. This + record contains the name of the module. There is one module record for each relocatable + object created by the assembler. The name of the relocatable object module + contained in the record comes from the IDNT directive. For absolute objects created + by the linker, there is one module record for each relocatable object file linked, + plus an additional record whose name comes from the NAME command for the + linker. + + Example: + + $$ MODNAME + + +Symbol Record (Optional) + + As many symbol records as needed can be contained in the object module. Up to 4 + symbols per line can be used, but it is not mandatory that each line contain 4 + symbols. A module can contain only symbol records. + + Example: + + APPLE $00000 LABEL1 $ODOC3 + MEM $OFFFF ZEEK $01947 + + The module name associated with the symbols can be specified in the + module_record preceding the symbol records. + + Example: + + $$MAIN + + Symbols are assumed to be in the module named in the preceding module_record + until another module is specified with another module_record. Symbols defined by + the linker's PUBLIC command appear following the first module record, which + indicates the name of the output object module specified by the linker's NAME + command. + + +***************************************************************************************** + +Header Record (SO) + + Each object module has exactly one header record with the following format: + + S00600004844521B + + Description: + + S0 Identifies the record as a header record + 06 The number of bytes following this one + 0000 The address field, which is ignored + 484452 The string HDR in ASCII + 1B The checksum + + + +***************************************************************************************** + +Data Record (S1) + + A data record specifies data bytes that are to be loaded into memory. Figure 1 + shows the format for such a record. The columns shown in the figure represent half + of a byte (4 bits). + + --------------------------------------------- + | 1 2 3 4 5 6 7 8 9 ... 40 41 42 | + | | + | S ID byte load data...data checksum | + | count address 1 n | + --------------------------------------------- + Figure 1: Data Record Formatter 16-Bit Load Address + + + Column Description + + 1 Contains the ASCII character S, which indicates the start of + a record in Motorola S-record format. + + 2 Contains the ASCII character identifying the record type. + For data records, this character is 1. + + 3 to 4 Contain the count of the number of bytes following this one + within the record. The count includes the checksum and the + load address bytes but not the byte count itself. + + 5 to 8 Contain the load address. The first data byte is to be loaded + into this address and subsequent bytes into the next sequential + address. Columns 5 and 6 contain the high-order address + byte, and columns 7 and 8 contain the low-order address byte. + + 9 to 40 Contain the specifications for up to 16 bytes of data. + + 41 to 42 Contain a checksum for the record. To calculate this, take the + sum of the values of all bytes from the byte count up to the + last data byte, inclusive, modulo 256. Subtract this result + from 255. + + +***************************************************************************************** + +Data Record (S2) + + + A data record specifies data bytes that are to be loaded into memory. Figure 2 + shows the format for such a record. The columns shown in the figure represent half + of a byte (4 bits). + + + ---------------------------------------------------- + | 1 2 3 4 5 6 7 8 9 10 11 ... 42 43 44 | + | | + | S ID byte load data...data checksum | + | count address 1 n | + ---------------------------------------------------- + Figure 2: Data Record Format for 24-Bit Load Address + + Column Description + + 1 Contains the ASCII character S, which indicates the start of + a record in Motorola S-record format. + + 2 Contains the ASCII character identifying the record type. + For data records, this character is 2. + + 3 to 4 Contain the count of the number of bytes following this one + within the record. The count includes the checksum and the + load address bytes but not the byte count itself. + + 5 to 10 Contain the load address. The first data byte is to be loaded + into this address and subsequent bytes into the next sequential + address. Columns 5 and 6 contain the high-order address + byte, and columns 9 and 10 contain the low-order address byte. + + 11 to 42 Contain the specifications for up to 16 bytes of data. + + 43 to 44 Contain a checksum for the record. To calculate this, take the + sum of the values of all bytes from the byte count up to the + last data byte, inclusive, modulo 256. Subtract this result + from 255. + + +***************************************************************************************** + +Data Record (S3) + + + A data record specifies data bytes that are to be loaded into memory. Figure 3 + shows the format for such a record. The columns shown in the figure represent half + of a byte (4 bits). + + ---------------------------------------------------------- + | 1 2 3 4 5 6 7 8 9 10 11 12 13 ... 44 45 46 | + | | + | S ID byte load data...data checksum | + | count address 1 n | + ---------------------------------------------------------- + Figure 3: Data Record Format for 32-Bit Load Address + + Column Description + + 1 Contains the ASCII character S, which indicates the start of + a record in Motorola S-record format. + + 2 Contains the ASCII character identifying the record type. + For data records, this digit is 3 for 32-bit addresses. + + 3 to 4 Contain the count of the number of bytes following this one + within the record. The count includes the checksum and the + load address bytes but not the byte count itself. + + 5 to 12 Contain the load address. The first data byte is to be loaded + into this address and subsequent bytes into the next sequential + address. Columns 5 and 6 contain the high-order address + byte, and columns 11 and 12 contain the low-order address byte. + + 13 to 44 Contain the specifications for up to 15 bytes of data. + + 45 to 46 Contain a checksum for the record. To calculate this, take the + sum of the values of all bytes from the byte count up to the + last data byte, inclusive, modulo 256. Subtract this result + from 255. + + +***************************************************************************************** + +Record Count Record (S5) + + + The record count record verifies the number of data records preceding it. Figure 4 + shows the format for such a record. The columns shown in the figure represent half + of a byte (4 bits). + + -------------------------------------- + | 1 2 3 4 5 6 7 8 9 10 | + | | + | S ID byte # of data checksum | + | count records | + -------------------------------------- + Figure 4: Record Count Record Format + + Column Description + + 1 Contains the ASCII character S, which indicates the start of + a record in Motorola S-record format. + + 2 Contains the ASCII character 5, which indicates a record + count record. + + 3 to 4 Contain the byte count, ASCII string 03. + + 5 to 8 Contain the number of data records in this file. The high- + order byte is in columns 5 and 6. + + 9 to 10 Contain the checksum for the record. + + Example: + + S503010DEE + + The example above shows a record count record indicating a total of 269 records + (0x010D) and a checksum of 0xEE. + + + +***************************************************************************************** + +Terminator Record for 32-bit address (S7) + + A terminator record specifies the end of the data records. Figure 5 shows the + format for such a record. The columns shown in the figure represent half of a byte + (4 bits). + + ------------------------------------- + | 1 2 3 4 5...12 13 14 | + | | + | S ID byte load checksum | + | count address | + ------------------------------------- + Figure5: Terminator Record Format for 32-Bit Load Address + + Column Description + + 1 Contains the ASCII character S, which indicates the start of + a record in Motorola S-record format. + + 2 Contains the ASCII character 7, which indicates a 32-bit + load address. + + 3 to 4 Contain the byte count, ASCII string 04. + + 5 to 12 Contain the load address that is either set to zero or to the + starting address specified in the END directive or START + command (there are no data bytes). + + 13 to 14 Contain the checksum for the record. + +***************************************************************************************** + +Terminator Record for 24-bit address (S8) + + + A terminator record specifies the end of the data records. Figure 6 shows the + format for such a record. The columns shown in the figure represent half of a byte + (4 bits). + + ---------------------------------------- + | 1 2 3 4 5 6 7 8 9 10 11 12 | + | | + | S ID byte load checksum | + | count address | + ---------------------------------------- + Figure 6: Terminator Record Format for 24-Bit Load Address + + Column Description + + 1 Contains the ASCII character S, which indicates the start of + a record in Motorola S-record format. + + 2 Contains the ASCII character 8, which indicates a 24-bit + load address. + + 3 to 4 Contain the byte count, ASCII string 04. + + 5 to 10 Contain the load address, which is either set to zero or to the + starting address specified in the END directive or START + command. There are no data bytes. + + 11 to 12 Contain the checksum for the record. + + Example: + + S804000AF0001 + + The previous example shows a terminator record with a 24-bit load address of + 0x000AF0 and a checksum of 0x01. + + +***************************************************************************************** + +Terminator Record for 16-bit address (S9) + + + A terminator record specifies the end of the data records. Figure 7 shows the + format for such a record. The columns shown in the figure represent half of a byte + (4 bits). + + ------------------------------------- + | 1 2 3 4 5 6 7 8 9 10 | + | | + | S ID byte load checksum | + | count address | + ------------------------------------- + Figure 7: Terminator Record Format for 16-Bit Load Address + + + Column Description + + 1 Contains the ASCII character S, which indicates the start of + a record in Motorola S-record format. + + 2 Contains the ASCII character 9, which indicates a 16-bit + load address. + + 3 to 4 Contain the byte count, ASCII string 04. + + 5 to 8 Contain the load address, which is either set to zero or to the + starting address specified in the END directive or START + command (there are no data bytes). + + 9 to 10 Contain the checksum for the record. + + + +***************************************************************************************** + hagen.v.tronje@on-line.de diff --git a/tools/hex2bin-2.0/doc/formats.txt b/tools/hex2bin-2.0/doc/formats.txt new file mode 100644 index 0000000..25e5e37 --- /dev/null +++ b/tools/hex2bin-2.0/doc/formats.txt @@ -0,0 +1,72 @@ +Hex formats + +Intel +===== + +Hexadecimal values are always in uppercase. Each line is a record. +The sum of all the bytes in each record should be 00 (modulo 256). + +Record types: + +00: data records +01: end-of-file record +02: extended address record + +Data record +----------- + + :0D011C0000000000C3E0FF0000000000C30F + +: 0D 011C 00 00000000C3E0FF0000000000C3 0F +| | | | -------------+------------ | +| | | | | +--- Checksum +| | | | +------------------ Data bytes +| | | +--------------------------------- Record type +| | +------------------------------------- Address +| +----------------------------------------- Number of data bytes ++-------------------------------------------- Start of record + + +End of file record +------------------ + + :00000001FE + +: 00 0000 01 FE +| | | | | +| | | | +--- Checksum +| | | +------ Record type +| | +---------- Address +| +-------------- Number of data bytes ++----------------- Start of record + + + +Extended address record +----------------------- + + :02010002E0001B + +: 02 0100 02 E000 1B +| | | | | | +| | | | | +--- Checksum +| | | | +-------- Segment address +| | | +----------- Record type +| | +--------------- Address +| +------------------- Number of data bytes ++---------------------- Start of record + +Following data records will start at E000:0100 or E0100 + + + + + + + + + + + + + diff --git a/tools/hex2bin-2.0/doc/intelhex.spc b/tools/hex2bin-2.0/doc/intelhex.spc new file mode 100644 index 0000000..946d586 --- /dev/null +++ b/tools/hex2bin-2.0/doc/intelhex.spc @@ -0,0 +1,409 @@ + +====================================================================== + +Intel +Hexadecimal Object File +Format Specification +Revision A, 1/6/88 + + + +DISCLAIMER + +Intel makes no representation or warranties with respect to the contents +hereof and specifically disclaims any implied warranties of +merchantability or fitness for any particular purpose. Further, Intel +reserves the right to revise this publication from time to time in the +content hereof without obligation of Intel to notify any person of such +revision or changes. The publication of this specification should not +be construed as a commitment on Intel's part to implement any product. + + +1. Introduction +This document describes the hexadecimal object file format for the Intel +8- bit, 16-bit, and 32-bit microprocessors. The hexadecimal format is +suitable as input to PROM programmers or hardware emulators. +Hexadecimal object file format is a way of representing an absolute +binary object file in ASCII. Because the file is in ASCII instead of +binary, it is possible to store the file is non-binary medium such as +paper-tape, punch cards, etc.; and the file can also be displayed on CRT +terminals, line printers, etc.. The 8-bit hexadecimal object file +format allows for the placement of code and data within the 16-bit +linear address space of the Intel 8-bit processors. The 16-bit +hexadecimal format allows for the 20-bit segmented address space of the +Intel 16-bit processors. And the 32-bit format allows for the 32-bit +linear address space of the Intel 32-bit processors. +The hexadecimal representation of binary is coded in ASCII alphanumeric +characters. For example, the 8-bit binary value 0011-1111 is 3F in +hexadecimal. To code this in ASCII, one 8-bit byte containing the ASCII +code for the character '3' (0011-0011 or 033H) and one 8-bit byte +containing the ASCII code for the character 'F' (0100-0110 or 046H) are +required. For each byte value, the high-order hexadecimal digit is +always the first digit of the pair of hexadecimal digits. This +representation (ASCII hexadecimal) requires twice as ma ny bytes as the +binary representation. +A hexadecimal object file is blocked into records, each of which +contains the record type, length, memory load address and checksum in +addition to the data. There are currently six (6) different types of +records that are defined, not all combinations of these records are +meaningful, however. The records are: + +Data Record (8-, 16-, or 32-bit formats) +End of File Record (8-, 16-, or 32-bit formats) +Extended Segment Address Record (16- or 32-bit formats) +Start Segment Address Record (16- or 32-bit formats) +Extended Linear Address Record (32-bit format only) +Start Linear Address Record (32-bit format only) + + +2. General Record Format +| RECORD | LOAD | | | INFO | | +| MARK | RECLEN | OFFSET | RECTYP | or | CHKSUM | +| ':' | | | | DATA | | + 1-byte 1-byte 2-bytes 1-byte n-bytes 1-byte + +Each record begins with a RECORD MARK field containing 03AH, the ASCII +code for the colon (':') character. +Each record has a RECLEN field which specifies the number of bytes of +information or data which follows the RECTYP field of the record. Note +that one data byte is represented by two ASCII characters. The maximum +value of the RECLEN field is hexadecimal 'FF' or 255. +Each record has a LOAD OFFSET field which specifies the 16-bit starting +load offset of the data bytes, therefore this field is only used for +Data Records. In other records where this field is not used, it should +be coded as four ASCII zero characters ('0000' or 030303030H). +Each record has a RECTYP field which specifies the record type of this +record. The RECTYP field is used to interpret the remaining information +within the record. The encoding for all the current record types are: + +'00' Data Record +'01' End of File Record +'02' Extended Segment Address Record +'03' Start Segment Address Record +'04' Extended Linear Address Record +'05' Start Linear Address Record + +Each record has a variable length INFO/DATA field, it consists of zero +or more bytes encoded as pairs of hexadecimal digits. The +interpretation of this field depends on the RECTYP field. +Each record ends with a CHKSUM field that contains the ASCII hexadecimal +representation of the two's complement of the 8-bit bytes that result +from converting each pair of ASCII hexadecimal digits to one byte of +binary, from and including the RECLEN field to and including the last +byte of the INFO/DATA field. Therefore, the sum of all the ASCII pairs +in a record after converting to binary, from the RECLEN field to and +including the CHKSUM field, is zero. + + +3. Extended Linear Address Record (32-bit format only) +| RECORD | LOAD | | | | | +| MARK | RECLEN | OFFSET | RECTYP | ULBA | CHKSUM | +| ':' | '02' | '0000' | '04' | | | + 1-byte 1-byte 2-bytes 1-byte 2-bytes 1-byte + +The 32-bit Extended Linear Address Record is used to specify bits 16-31 +of the Linear Base Address (LBA), where bits 0-15 of the LBA are zero. +Bits 16-31 of the LBA are referred to as the Upper Linear Base Address +(ULBA). The absolute memory address of a content byte in a subsequent +Data Record is obtained by adding the LBA to an offset calculated by +adding the LOAD OFFSET field of the containing Data Record to the index +of the byte in the Data Record (0, 1, 2, ... n). This offset addition +is done modulo 4G (i.e., 32-bits), ignoring any carry, so that offset +wrap-around loading (from OFFFFFFFFH to OOOOOOOOOH) results in wrapping +around from the end to the beginning of the 4G linear address defined by +the LBA. The linear address at which a particular byte is loaded is +calculated as: +(LBA + DRLO + DRI) MOD 4G +where: +DRLO is the LOAD OFFSET field of a Data Record. +DRI is the data byte index within the Data Record. + +When an Extended Linear Address Record defines the value of LBA, it may +appear anywhere within a 32-bit hexadecimal object file. This value +remains in effect until another Extended Linear Address Record is +encountered. The LBA defaults to zero until an Extended Linear Address +Record is encountered. +The contents of the individual fields within the record are: + +RECORD MARK +This field contains 03AH, the hexadecimal encoding of the ASCII colon +(':') character. + +RECLEN +The field contains 03032H, the hexadecimal encoding of the ASCII +characters '02', which is the length, in bytes, of the ULBA data +information within this record. + +LOAD OFFSET +This field contains 030303030H, the hexadecimal encoding of the ASCII +characters '0000', since this field is not used for this record. + +RECTYP +This field contains 03034H, the hexadecimal encoding of the ASCII +character '04', which specifies the record type to be an Extended Linear +Address Record. + +ULBA +This field contains four ASCII hexadecimal digits that specify the +16-bit Upper Linear Base Address value. The high-order byte is the +10th/llth character pair of the record. The low-order byte is the +12th/13th character pair of the record. + +CHKSUM +This field contains the check sum on the RECLEN, LOAD OFFSET, RECTYP, +and ULBA fields. + + +4. Extended Segment Address Record (16- or 32-bit formats) +| RECORD | LOAD | | | | | +| MARK | RECLEN | OFFSET | RECTYP | USBA | CHKSUM | +| ':' | '02' | '0000' | '02' | | | + 1-byte 1-byte 2-bytes 1-byte 2-bytes 1-byte + +The 16-bit Extended Segment Address Record is used to specify bits 4-19 +of the Segment Base Address (SBA), where bits 0-3 of the SBA are zero. +Bits 4-19 of the SBA are referred to as the Upper Segment Base Address +(USBA). The absolute memory address of a content byte in a subsequent +Data Record is obtained by adding the SBA to an offset calculated by +adding the LOAD OFFSET field of the containing Data Record to the index +of the byte in the Data Record (0, 1, 2, ... n). This offset addition +is done modulo 64K (i.e., 16-bits), ignoring any carry, so that offset +wraparound loading (from OFFFFH to OOOOOH) results in wrapping around +from the end to the beginning of the 64K segment defined by the SBA. +The address at which a particular byte is loaded is calculated as: + + SBA + ([DRLO + DRI] MOD 64K) + +where: + DRLO is the LOAD OFFSET field of a Data Record. + DRI is the data byte index within the Data Record. + +When an Extended Segment Address Record defines the value of SBA, it +may appear anywhere within a 16-bit hexadecimal object file. This +value remains in effect until another Extended Segment Address +Record is encountered. The SBA defaults to zero until an Extended +Segment Address Record is encountered. + +The contents of the individual fields within the record are: + +RECORD MARK +This field contains 03AH, the hexadecimal encoding of the ASCII +colon (':') character. + +RECLEN +The field contains 03032H, the hexadecimal encoding of the ASCII +characters '02', which is the length, in bytes, of the USBA data +information within this record. + +LOAD OFFSET +This field contains 030303030H, the hexadecimal encoding of the +ASCII characters '0000', since this field is not used for this +record. + +RECTYP +This field contains 03032H, the hexadecimal encoding of the ASCII +character '02', which specifies the record type to be an Extended +Segment Address Record. + +USBA +This field contains four ASCII hexadecimal digits that specify the +16-bit Upper Segment Base Address value. The high-order byte is the +10th/1lth character pair of the record. The low-order byte is the +12th/13th character pair of the record. + +CHKSUM +This field contains the check sum on the RECLEN, LOAD OFFSET, +RECTYP, and USBA fields. + +5. Data Record (8-, 16-, or 32-bit formats) + +| RECORD | LOAD | | | | | +| MARK | RECLEN | OFFSET | RECTYP | DATA | CHKSUM | +| ':' | | | '00' | | | + 1-byte 1-byte 2-bytes 1-byte n-bytes 1-byte + + +The Data Record provides a set of hexadecimal digits that represent +the ASCII code for data bytes that make up a portion of a memory +image. The method for calculating the absolute address (linear in +the 8-bit and 32-bit case and segmented in the 16-bit case) for each +byte of data is described in the discussions of the Extended Linear +Address Record and the Extended Segment Address Record. + +The contents of the individual fields within the record are: + +RECORD MARK +This field contains 03AH, the hexadecimal encoding of the ASCII +colon (':') character. + +RECLEN +The field contains two ASCII hexadecimal digits that specify the +number of data bytes in the record. The maximum value is 'FF' or +04646H (255 decimal). + +LOAD OFFSET +This field contains four ASCII hexadecimal digits representing the +offset from the LBA (see Extended Linear Address Record) or SBA (see +Extended Segment Address Record) defining the address which the +first byte of the data is to be placed. + +RECTYP +This field contains 03030H, the hexadecimal encoding of the ASCII +character '00', which specifies the record type to be a Data Record. + +DATA +This field contains pairs of ASCII hexadecimal digits, one pair for +each data byte. + +CHKSUM +This field contains the check sum on the RECLEN, LOAD OFFSET, +RECTYP, and DATA fields. + + +6. Start Linear Address Record (32-bit format only) + +| RECORD | LOAD | | | | | +| MARK | RECLEN | OFFSET | RECTYP | EIP | CHKSUM | +| ':' | '04' | '0000' | '05' | | | + 1-byte 1-byte 2-bytes 1-byte 4-bytes 1-byte + + +The Start Linear Address Record is used to specify the execution +start address for the object file. The value given is the 32-bit +linear address for the EIP register. Note that this record only +specifies the code address within the 32-bit linear address space of +the 80386. If the code is to start execution in the real mode of +the 80386, then the Start Segment Address Record should be used +instead, since that record specifies both the CS and IP register +contents necessary for real mode. + +The Start Linear Address Record can appear anywhere in a 32-bit +hexadecimal object file. If such a record is not present in a +hexadecimal object file, a loader is free to assign a default start +address. + +The contents of the individual fields within the record are: + +RECORD MARK +This field contains 03AH, the hexadecimal encoding of the ASCII +colon (':') character. + +RECLEN +The field contains 03034H, the hexadecimal encoding of the ASCII +characters '04', which is the length, in bytes, of the EIP register +content within this record. + +LOAD OFFSET +This field contains 030303030H, the hexadecimal encoding of the +ASCII characters '0000', since this field is not used for this +record. + +RECTYP +This field contains 03035H, the hexadecimal encoding of the ASCII +character '05', which specifies the record type to be a Start Linear +Address Record. + +EIP +This field contains eight ASCII hexadecimal digits that specify the +32-bit EIP register contents. The high-order byte is the 10th/1lth +character pair. + +CHKSUM +This field contains the check sum on the RECLEN, LOAD OFFSET, +RECTYP, and EIP fields. + + +7. Start Segment Address Record (16- or 32-bit formats) + +| RECORD | LOAD | | | | | +| MARK | RECLEN | OFFSET | RECTYP | CS/IP | CHKSUM | +| ':' | '04' | '0000' | '03' | | | + 1-byte 1-byte 2-bytes 1-byte 4-bytes 1-byte + + +The Start Segment Address Record is used to specify the execution +start address for the object file. The value given is the 20-bit +segment address for the CS and IP registers. Note that this record +only specifies the code address within the 20-bit segmented address +space of the 8086/80186. + +The Start Segment Address Record can appear anywhere in a 16-bit +hexadecimal object file. If such a record is not present in a +hexadecimal object file, a loader is free to assign a default start +address. + +The contents of the individual fields within the record are: + +RECORD MARK +This field contains 03AH, the hexadecimal encoding of the ASCII +colon (':') character. + +RECLEN +The field contains 03034H, the hexadecimal encoding of the ASCII +characters '04', which is the length, in bytes, of the CS/IP +register contents within this record. + +LOAD OFFSET +This field contains 030303030H, the hexadecimal encoding of the +ASCII characters '0000', since this field is not used for this +record. + +RECTYP +This field contains 03033H, the hexadecimal encoding of the ASCII +character '03', which specifies the record type to be a Start +Segment Address Record. + +CS/IP +This field contains eight ASCII hexadecimal digits that specify the +16-bit CS register and 16-bit IP register contents. The high-order +byte of the CS register content is the 10th/llth character pair, the +low-order byte is the 12th/13th character pair of the record. The +high-order byte of the IP register content is the 14th/15th +character pair, the low-order byte is the 16th/17th character pair +of the record. + +CHKSUM +This field contains the check sum on the RECLEN, LOAD OFFSET, +RECTYP, and CS/IP fields. + + + +8. End of File Record (8-, 16-, or 32-bit formats) + +| RECORD | LOAD | | | | +| MARK | RECLEN | OFFSET | RECTYP | CHKSUM | +| ':' | '00' | '0000' | '01' | | + 1-byte 1-byte 2-bytes 1-byte 1-byte + +The End of File Record specifies the end of the hexadecimal object +file. + +The contents of the individual fields within the record are: + +RECORD MARK +This field contains 03AH, the hexadecimal encoding of the ASCII +colon (':') character. + +RECLEN +The field contains 03030H, the hexadecimal encoding of the ASCII +characters '00'. Since this record does not contain any INFO/DATA +bytes, the length is zero. + +LOAD OFFSET +This field contains 030303030H, the hexadecimal encoding of the +ASCII characters '0000', since this field is not used for this +record. + +RECTYP +This field contains 03031H, the hexadecimal encoding of the ASCII +character '01', which specifies the record type to be an End of File +Record. + +CHKSUM +This field contains the check sum an the RECLEN, LOAD OFFSET, and +RECTYP fields. Since all the fields are static, the check sum can +also be calculated statically, and the value is 04646H, the +hexadecimal encoding of the ASCII characters 'FF'. + +======================================================================== +END diff --git a/tools/hex2bin-2.0/doc/srec.txt b/tools/hex2bin-2.0/doc/srec.txt new file mode 100644 index 0000000..ea63d31 --- /dev/null +++ b/tools/hex2bin-2.0/doc/srec.txt @@ -0,0 +1,447 @@ +S-Records + + + -S-Record Format- + + Chaplin@keinstr.uucp (Roger Chaplin) reposted an article written + by mcdchg!motmpl!ron (Ron Widell) that explained how Motorola + S-Records are formatted. This comes from a unix man page. No + mention of which version of Unix is specified. This section + of the FAQ is a bit long. An anonymous ftp archive is currently + being sought. When one is found, the section will be placed in + the archive. + + + SREC(4) UNIX 5.0 (03/21/84) SREC(4) + + + An S-record file consists of a sequence of specially formatted + ASCII character strings. An S-record will be less than or equal to + 78 bytes in length. + + The order of S-records within a file is of no significance and no + particular order may be assumed. + + The general format of an S-record follow: + + +------------------//-------------------//-----------------------+ + | type | count | address | data | checksum | + +------------------//-------------------//-----------------------+ + + type A char-2- field. These characters describe the + type of record (S0, S1, S2, S3, S5, S7, S8, or + S9). + count A char-2- field. These characters when paired and + interpreted as a hexadecimal value, display the + count of remaining character pairs in the record. + + address A char-4,6, or 8- field. These characters grouped + and interpreted as a hexadecimal value, display + the address at which the data field is to be + loaded into memory. The length of the field + depends on the number of bytes necessary to hold + the address. A 2-byte address uses 4 characters, + a 3-byte address uses 6 characters, and a 4-byte + address uses 8 characters. + data A char -0-64- field. These characters when paired + and interpreted as hexadecimal values represent + the memory loadable data or descriptive + information. + + checksum A char-2- field. These characters when paired and + interpreted as a hexadecimal value display the + least significant byte of the ones complement of + the sum of the byte values represented by the + pairs of characters making up the count, the + address, and the data fields. + + Each record is terminated with a line feed. If any + additional or different record terminator(s) or delay + characters are needed during transmission to the target + system it is the responsibility of the transmitting program + to provide them. + + S0 Record The type of record is 'S0' (0x5330). The address + + + field is unused and will be filled with zeros + (0x0000). The header information within the data + field is divided into the following subfields. + + mname is char-20- and is the + module name. + ver is char-2- and is the + version number. + + rev is char-2- and is the + revision number. + description is char-0-36- and is a + text comment. + + Each of the subfields is composed of ASCII bytes + whose associated characters, when paired, + represent one byte hexadecimal values in the case + of the version and revision numbers, or represent + the hexadecimal values of the ASCII characters + comprising the module name and description. + + S1 Record The type of record field is 'S1' (0x5331). The + address field is interpreted as a 2-byte address. + The data field is composed of memory loadable + data. + S2 Record The type of record field is 'S2' (0x5332). The + address field is interpreted as a 3-byte address. + The data field is composed of memory loadable + data. + + S3 Record The type of record field is 'S3' (0x5333). The + address field is interpreted as a 4-byte address. + The data field is composed of memory loadable + data. + S5 Record The type of record field is 'S5' (0x5335). The + address field is interpreted as a 2-byte value + and contains the count of S1, S2, and S3 records + previously transmitted. There is no data field. + + S7 Record The type of record field is 'S7' (0x5337). The + address field contains the starting execution + address and is interpreted as 4-byte address. + There is no data field. + S8 Record The type of record field is 'S8' (0x5338). The + address field contains the starting execution + address and is interpreted as 3-byte address. + There is no data field. + + S9 Record The type of record field is 'S9' (0x5339). The + address field contains the starting execution + address and is interpreted as 2-byte address. + There is no data field. + + EXAMPLE + + Shown below is a typical S-record format file. + + S00600004844521B + S1130000285F245F2212226A000424290008237C2A + S11300100002000800082629001853812341001813 + S113002041E900084E42234300182342000824A952 + S107003000144ED492 + S5030004F8 + S9030000FC + + The file consists of one S0 record, four S1 records, one S5 + record and an S9 record. + + The S0 record is comprised as follows: + + S0 S-record type S0, indicating it is a header + record. + 06 Hexadecimal 06 (decimal 6), indicating that six + character pairs (or ASCII bytes) follow. + + 00 00 Four character 2-byte address field, zeroes in + this example. + 48 ASCII H, D, and R - "HDR". + + 1B The checksum. + + The first S1 record is comprised as follows: + S1 S-record type S1, indicating it is a data record + to be loaded at a 2-byte address. + + 13 Hexadecimal 13 (decimal 19), indicating that + nineteen character pairs, representing a 2 byte + address, 16 bytes of binary data, and a 1 byte + checksum, follow. + 00 00 Four character 2-byte address field; hexadecimal + address 0x0000, where the data which follows is to + be loaded. + + 28 5F 24 5F 22 12 22 6A 00 04 24 29 00 08 23 7C Sixteen + character pairs representing the actual binary + data. + 2A The checksum. + + The second and third S1 records each contain 0x13 (19) + character pairs and are ended with checksums of 13 and 52, + respectively. The fourth S1 record contains 07 character + pairs and has a checksum of 92. + + The S5 record is comprised as follows: + + S5 S-record type S5, indicating it is a count record + indicating the number of S1 records. + + + + 03 Hexadecimal 03 (decimal 3), indicating that three + character pairs follow. + + 00 04 Hexadecimal 0004 (decimal 4), indicating that + there are four data records previous to this + record. + F8 The checksum. + + The S9 record is comprised as follows: + + S9 S-record type S9, indicating it is a termination + record. + 03 Hexadecimal 03 (decimal 3), indicating that three + character pairs follow. + + 00 00 The address field, hexadecimal 0 (decimal 0) + indicating the starting execution address. + FC The checksum. + + + -Intel Hex ASCII Format- + + Intel HEX-ASCII format takes the form: + + +----------------------------------- Start Character + | + | +-------------------------------- Byte Count + | | (# of data bytes) + | | + | | +-------------------------- Address of first data. + | | | + | | | +-------------------- Record Type (00 data, + | | | | 01 end of record) + | | | | + | | | | +------------ Data Bytes + | | | | | + | | | | | +---- Checksum + | | | | | | + | / \ / \ / \ / \ / \ + : B C A A A A T T H H ... H H C C + + An examples: + + :10000000DB00E60F5F1600211100197ED300C3004C + :1000100000000101030307070F0F1F1F3F3F7F7FF2 + :01002000FFE0 + :00000001FF + + This information comes from _Microprocessors and Programmed + Logic_, Second Edition, Kenneth L. Short, 1987, Prentice-Hall, + ISBN 0-13-580606-2. + + Provisions have been made for data spaces larger than 64 kBytes. + The above reference does not discuss them. I suspect there is + a start of segment type record, but I do not know how it is + implemented. + +---------------------------------------------------------------------------- + +/* This file contains source code to read a Motorola S-record file into +** a memory image. The size of the file cannot exceed BUFSIZE of data. +** The image is then written to disk either as binary data starting at +** address 0 with no data gaps, or as a C array of unsigned longs. +** Input lines must be no longer than MAXLINE. No check is made! +** +** Author: Eric McRae, Electro-Logic Machines, Inc. +** Date: Copyright 1994 +** +** This source code is made available to the public "as is". No +** warranty is given or implied for it's proper operation. This source +** code may be used in whole or in part as long as this copyright is +** included. +*/ +#include +#include +#include + +/* Comment the following line for non PC applications */ +#define PCDOS + +/* Uncomment the following line if you want a binary output instead of +** a structure +*/ +/* #define BINARY */ + +#ifdef PCDOS /* Intel x86 architecture */ +#define BUFSIZE 49152 /* 48K to avoid segment hopping */ +#else /* Any reasonable (non-segmented) arch... */ +#define BUFSIZE 65536 /* As big as you want */ +#endif + +#define MAXLINE 256 /* Length of longest input line + 1 */ +/* Globals */ +FILE *infilePH, *outfilePH; /* Handles for input and output files */ +unsigned char *bufAC, /* Allocated image buffer */ + *highestPC = NULL; /* Highest buffer address written */ + +/* Change this string to reflect the name of the output array */ +char headerAC[] = "unsigned long sRec[] =\n{\n"; + +/* Predeclarations */ +int parsebufN( char * ); /* Does the actual parsing */ + +void main(int argc, const char * argv[]) +{ + int c, /* Temp char storage */ + resN; /* result status */ + char *lbufPC, lbufAC[MAXLINE]; + int linectrN = 0; /* Used to correlate parse fail to input line */ + +#ifndef BINARY + int i; + unsigned long *codePL; + unsigned char *codePC; +#endif + + /* Check the argument count */ + if( argc != 3 ) /* If didn't specify input and output files */ + { + printf("Usage: %s: infile outfile\n", argv[0] ); + exit(1); + } + + /* OK, let's open some files */ + if( ( infilePH = fopen( argv[1], "r" ) )== NULL ) + { + printf("%s: Couldn't open input file %s\n", argv[0], argv[1] ); + exit(2); + } + + if( ( outfilePH = fopen( argv[2], "w" ) ) == NULL ) + { + printf("%s: Couldn't open output file %s\n", argv[0], argv[3] ); + exit(3); + } + + /* OK, get a buffer and clear it. */ + if( (bufAC = calloc( (size_t)BUFSIZE, (size_t)1 )) == NULL ) + { + printf("%s: Couldn't malloc memory for buffer\n", argv[0] ); + exit(4); + } + + lbufPC = lbufAC; /* Point at beginning of line buffer */ + while( c = fgetc( infilePH )) + { + if( (c == '\n') || (c == EOF) ) /* If found end of line or file */ + { /* Parse the Line */ + if( ( c == EOF ) && ( ferror( infilePH ) ) ) + { + printf("%s: Error reading input file\n", argv[0] ); + exit(5); + } + else + { /* OK, have a complete line in buffer */ + linectrN++; /* Increment line counter */ + if( lbufPC == lbufAC ) + break; /* ignore blank lines */ + *lbufPC = 0; /* Terminate the line string */ + if( resN = parsebufN( lbufAC ) ) /* Parse data record to mem */ + { + printf("%s: Error reading input file at line %d, return code = %d\n", + argv[0], linectrN, resN ); + exit( resN ); + } + lbufPC = lbufAC; /* Repoint line buffer pointer */ + } /* End of have a complete line */ + } + else + *lbufPC++ = c; /* Place char into line buffer */ + } + + /* At this point, the input file has been emptied. Now dispose of the + ** output data according to compilation mode. + */ + +#ifdef BINARY + + /* Write the buffer back to disk as a binary image */ + resN = fwrite( bufAC, 1, (size_t)((highestPC - bufAC) + 1), outfilePH ); + if( resN != (int)( (highestPC - bufAC) + 1) ) + { + printf("%s: Error writing output file\n", argv[0] ); + exit( 6 ); + } + +#else + /* Produce a file that can be included in a C program. Data is read + ** from buffer as bytes to avoid portability/endian problems with + ** this program. + */ + /* Output header first, then 1 long per line */ + fwrite( (void *)headerAC, 1, (size_t)(sizeof( headerAC )-1), outfilePH ); + + codePL = (unsigned long *)bufAC; + for( i = (highestPC - bufAC + 1) / 4; i; i-- ) /* for each long */ + { + codePC = (unsigned char *)codePL++; + sprintf(lbufAC, "0x%02x%02x%02x%02x%s", + *codePC, *(codePC + 1), *(codePC + 2), *(codePC + 3), + i == 1 ? "\n" : ",\n" ); /* No comma after final long */ + fwrite( lbufAC, 1, (size_t)(strlen( lbufAC )), outfilePH ); + } + /* OK, data has been written out, close end of array */ + fwrite( "};\n", 1, (size_t)3, outfilePH ); +#endif +} + +/* Function: parsebufV +** Parses an S-record in the buffer and writes it into the buffer +** if it is has a valid checksum. +** +** Args: pointer to character buffer for null terminated line +** Returns: int result code: 0 = success, else failure +*/ +int parsebufN( char *lbufPC ) +{ + unsigned long addrL; + unsigned char cksmB, /* checksum of addr, count, & data length */ + *bufPC; /* Pointer into memory array */ + int i, countN, /* Number of bytes represented in record */ + oheadN, /* Number of overhead (addr + chksum) bytes */ + tvalN; /* Temp for check checksum */ + + switch( *(lbufPC+1) ) /* examine 2nd character on the line */ + { + case '1': /* 16 bit address field */ + if( sscanf(lbufPC, "S1%2x%4lx", &countN, &addrL ) != 2 ) + return( 10 ); /* Flag error in S1 record */ + oheadN = 3; /* 2 address + 1 checksum */ + break; + + case '2': /* 24 bit address field */ + if( sscanf(lbufPC, "S2%2x%6lx", &countN, &addrL ) != 2 ) + return( 11 ); /* Flag error in S2 record */ + oheadN = 4; /* 3 address + 1 checksum */ + break; + + case '3': /* 32 bit address field */ + if( sscanf(lbufPC, "S3%2x%8lx", &countN, &addrL ) != 2 ) + return( 12 ); /* Flag error in S3 record */ + oheadN = 5; /* 4 address + 1 checksum */ + break; + + default: /* ignore all but S1,2,3 records. */ + return( 0 ); + } + + if( addrL > BUFSIZE ) return( 13 ); /* if address exceeds buffer size */ + bufPC = bufAC + addrL; /* otherwise, point to right spot in buffer */ + + /* OK now see if checksum is OK, while reading data to buffer */ + cksmB = 0; + countN++; /* Bump counter to read final checksum too */ + for( i = 1; i <= countN; i++ ) + { + sscanf( lbufPC + i*2, "%2x", &tvalN ); /* Scan a 2 hex digit byte */ + cksmB += (unsigned char)tvalN; + if( ( i > oheadN ) && ( i < countN ) ) /* If scanned a data byte */ + *bufPC++ = (unsigned char) tvalN; /* write it to the buffer */ + } + if( cksmB += 1 ) return( 14 ); /* flag checksum error */ + + if( (bufPC - 1) > highestPC ) + highestPC = bufPC - 1; /* track highest address loaded */ + + return( 0 ); /* Successful return */ +} + + + diff --git a/tools/hex2bin-2.0/src/binary.c b/tools/hex2bin-2.0/src/binary.c new file mode 100644 index 0000000..63ead0d --- /dev/null +++ b/tools/hex2bin-2.0/src/binary.c @@ -0,0 +1,196 @@ +/*---------------------------------------------------------------------------* + * binary.c * + * Copyright (C) 2014 Jacques Pelletier * + * * + * This program is free software; you can redistribute it and *or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation, * + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + *---------------------------------------------------------------------------*/ + +#include + +#include "binary.h" + +const uint8_t Reflect8[256] = { + 0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0, + 0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8, + 0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4, + 0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC, + 0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2, + 0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA, + 0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6, + 0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE, + 0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1, + 0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9, + 0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5, + 0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD, + 0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3, + 0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB, + 0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7, + 0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF, +}; + +uint16_t Reflect16(uint16_t Value16) +{ + return (((uint16_t) Reflect8[u16_lo(Value16)]) << 8) | ((uint16_t) Reflect8[u16_hi(Value16)]); +} + +uint32_t Reflect24(uint32_t Value24) +{ + return ( + (((uint32_t) Reflect8[u32_b0(Value24)]) << 16) | + (((uint32_t) Reflect8[u32_b1(Value24)]) << 8) | + ((uint32_t) Reflect8[u32_b2(Value24)]) + ); +} + +uint32_t Reflect32(uint32_t Value32) +{ + return ( + (((uint32_t) Reflect8[u32_b0(Value32)]) << 24) | + (((uint32_t) Reflect8[u32_b1(Value32)]) << 16) | + (((uint32_t) Reflect8[u32_b2(Value32)]) << 8) | + ((uint32_t) Reflect8[u32_b3(Value32)]) + ); +} + +uint64_t Reflect40(uint64_t Value40) +{ + return ( + (((uint64_t) Reflect8[u64_b0(Value40)]) << 32) | + (((uint64_t) Reflect8[u64_b1(Value40)]) << 24) | + (((uint64_t) Reflect8[u64_b2(Value40)]) << 16) | + (((uint64_t) Reflect8[u64_b3(Value40)]) << 8) | + ((uint64_t) Reflect8[u64_b4(Value40)]) + ); +} + +uint64_t Reflect64(uint64_t Value64) +{ + return ( + (((uint64_t) Reflect8[u64_b0(Value64)]) << 56) | + (((uint64_t) Reflect8[u64_b1(Value64)]) << 48) | + (((uint64_t) Reflect8[u64_b2(Value64)]) << 40) | + (((uint64_t) Reflect8[u64_b3(Value64)]) << 32) | + (((uint64_t) Reflect8[u64_b4(Value64)]) << 24) | + (((uint64_t) Reflect8[u64_b5(Value64)]) << 16) | + (((uint64_t) Reflect8[u64_b6(Value64)]) << 8) | + ((uint64_t) Reflect8[u64_b7(Value64)]) + ); +} + +uint8_t u16_hi(uint16_t value) +{ + return (uint8_t)((value & 0xFF00) >> 8); +} + +uint8_t u16_lo(uint16_t value) +{ + return (uint8_t)(value & 0x00FF); +} + +uint8_t u32_b3(uint32_t value) +{ + return (uint8_t)((value & 0xFF000000) >> 24); +} + +uint8_t u32_b2(uint32_t value) +{ + return (uint8_t)((value & 0x00FF0000) >> 16); +} + +uint8_t u32_b1(uint32_t value) +{ + return (uint8_t)((value & 0x0000FF00) >> 8); +} + +uint8_t u32_b0(uint32_t value) +{ + return (uint8_t)(value & 0x000000FF); +} + +uint8_t u64_b7(uint64_t value) +{ + return (uint8_t)((value & 0xFF00000000000000) >> 56); +} + +uint8_t u64_b6(uint64_t value) +{ + return (uint8_t)((value & 0x00FF000000000000) >> 48); +} + +uint8_t u64_b5(uint64_t value) +{ + return (uint8_t)((value & 0x0000FF0000000000) >> 40); +} + +uint8_t u64_b4(uint64_t value) +{ + return (uint8_t)((value & 0x000000FF00000000) >> 32); +} + +uint8_t u64_b3(uint64_t value) +{ + return (uint8_t)((value & 0x00000000FF000000) >> 24); +} + +uint8_t u64_b2(uint64_t value) +{ + return (uint8_t)((value & 0x0000000000FF0000) >> 16); +} + +uint8_t u64_b1(uint64_t value) +{ + return (uint8_t)((value & 0x000000000000FF00) >> 8); +} + +uint8_t u64_b0(uint64_t value) +{ + return (uint8_t)(value & 0x00000000000000FF); +} + +/* Checksum/CRC conversion to ASCII */ +uint8_t nibble2ascii(uint8_t value) +{ + uint8_t result = value & 0x0f; + + if (result > 9) return result + 0x41-0x0A; + else return result + 0x30; +} + +bool cs_isdecdigit(char c) +{ + return (c >= 0x30) && (c < 0x3A); +} + +unsigned char tohex(unsigned char c) +{ + if ((c >= '0') && (c < '9'+1)) + return (c - '0'); + if ((c >= 'A') && (c < 'F'+1)) + return (c - 'A' + 0x0A); + if ((c >= 'a') && (c < 'f'+1)) + return (c - 'a' + 0x0A); + + return 0; +} + +unsigned char todecimal(unsigned char c) +{ + if ((c >= '0') && (c < '9'+1)) + return (c - '0'); + + return 0; +} + + diff --git a/tools/hex2bin-2.0/src/binary.h b/tools/hex2bin-2.0/src/binary.h new file mode 100644 index 0000000..198589b --- /dev/null +++ b/tools/hex2bin-2.0/src/binary.h @@ -0,0 +1,36 @@ +#ifndef _BINARY_H_ +#define _BINARY_H_ + +typedef enum {false, true} bool; + +extern const unsigned char Reflect8[256]; + +uint16_t Reflect16(uint16_t Value16); +uint32_t Reflect24(uint32_t Value24); +uint32_t Reflect32(uint32_t Value32); +uint64_t Reflect40(uint64_t Value40); +uint64_t Reflect64(uint64_t Value64); + +uint8_t u16_hi(uint16_t value); +uint8_t u16_lo(uint16_t value); + +uint8_t u32_b3(uint32_t value); +uint8_t u32_b2(uint32_t value); +uint8_t u32_b1(uint32_t value); +uint8_t u32_b0(uint32_t value); + +uint8_t u64_b7(uint64_t value); +uint8_t u64_b6(uint64_t value); +uint8_t u64_b5(uint64_t value); +uint8_t u64_b4(uint64_t value); +uint8_t u64_b3(uint64_t value); +uint8_t u64_b2(uint64_t value); +uint8_t u64_b1(uint64_t value); +uint8_t u64_b0(uint64_t value); + +uint8_t nibble2ascii(uint8_t value); +bool cs_isdecdigit(char c); +unsigned char tohex(unsigned char c); +unsigned char todecimal(unsigned char c); + +#endif /* _BINARY_H_ */ diff --git a/tools/hex2bin-2.0/src/common.c b/tools/hex2bin-2.0/src/common.c new file mode 100644 index 0000000..f453dc4 --- /dev/null +++ b/tools/hex2bin-2.0/src/common.c @@ -0,0 +1,527 @@ +#include "common.h" + +filetype Filename; /* string for opening files */ +char Extension[MAX_EXTENSION_SIZE]; /* filename extension for output files */ + +FILE *Filin, /* input files */ + *Filout; /* output files */ + +#ifdef USE_FILE_BUFFERS +char *FilinBuf, /* text buffer for file input */ + *FiloutBuf; /* text buffer for file output */ +#endif + +int Pad_Byte = 0xFF; +bool Enable_Checksum_Error = false; +bool Status_Checksum_Error = false; +byte Checksum; +unsigned int Record_Nb; + +/* This will hold binary codes translated from hex file. */ +byte *Memory_Block; +unsigned int Lowest_Address, Highest_Address; +unsigned int Starting_Address; +unsigned int Max_Length = 0; +unsigned int Minimum_Block_Size = 0x1000; // 4096 byte +int Module; +bool Minimum_Block_Size_Setted = false; +bool Starting_Address_Setted = false; +bool Max_Length_Setted = false; +bool Swap_Wordwise = false; + +int Endian = 0; + +t_CRC Cks_Type = CHK8_SUM; +unsigned int Cks_Start = 0, Cks_End = 0, Cks_Addr = 0, Cks_Value = 0; +bool Cks_range_set = false; +bool Cks_Addr_set = false; +bool Force_Value = false; + +unsigned int Crc_Poly = 0x07, Crc_Init = 0, Crc_XorOut = 0; +bool Crc_RefIn = false; +bool Crc_RefOut = false; + +void usage(void) +{ + fprintf (stderr, + "\n" + "usage: %s [OPTIONS] filename\n" + "Options:\n" + " -c Enable record checksum verification\n" + " -C [Poly][Init][RefIn][RefOut][XorOut]\n CRC parameters" + " -e [ext] Output filename extension (without the dot)\n" + " -E [0|1] Endian for checksum/CRC, 0: little, 1: big\n" + " -f [address] Address of check result to write\n" + " -F [address] [value]\n Address and value to force\n" + " -k [0-4] Select check method (checksum or CRC) and size\n" + " -d display list of check methods/value size\n" + " -l [length] Maximal Length (Starting address + Length -1 is Max Address)\n" + " File will be filled with Pattern until Max Address is reached\n" + " -m [size] Minimum Block Size\n" + " File Size Dimension will be a multiple of Minimum block size\n" + " File will be filled with Pattern\n" + " Length must be a power of 2 in hexadecimal [see -l option]\n" + " Attention this option is STRONGER than Maximal Length \n" + " -p [value] Pad-byte value in hex (default: %x)\n" + " -r [start] [end]\n" + " Range to compute checksum over (default is min and max addresses)\n" + " -s [address] Starting address in hex (default: 0)\n" + " -w Swap wordwise (low <-> high)\n\n", + Pgm_Name,Pad_Byte); + exit(1); +} /* procedure USAGE */ + +void DisplayCheckMethods(void) +{ + fprintf (stderr, + "Check methods/value size:\n" + "0: Checksum 8-bit\n" + "1: Checksum 16-bit\n" + "2: CRC8\n" + "3: CRC16\n" + "4: CRC32\n"); + exit(1); +} + +#define LAST_CHECK_METHOD 4 + +void *NoFailMalloc (size_t size) +{ + void *result; + + if ((result = malloc (size)) == NULL) + { + fprintf (stderr,"Can't allocate memory.\n"); + exit(1); + } + return (result); +} + +/* Open the input file, with error checking */ +void NoFailOpenInputFile (char *Flnm) +{ + while ((Filin = fopen(Flnm,"r")) == NULL) + { + fprintf (stderr,"Input file %s cannot be opened. Enter new filename: ",Flnm); + if (fgets (Flnm,MAX_FILE_NAME_SIZE,stdin) == NULL) exit(1); /* modified error checking */ + + if (Flnm[strlen(Flnm) - 1] == '\n') Flnm[strlen(Flnm) - 1] = '\0'; + } + +#ifdef USE_FILE_BUFFERS + FilinBuf = (char *) NoFailMalloc (BUFFSZ); + setvbuf(Filin, FilinBuf, _IOFBF, BUFFSZ); +#endif +} /* procedure OPENFILIN */ + +/* Open the output file, with error checking */ +void NoFailOpenOutputFile (char *Flnm) +{ + while ((Filout = fopen(Flnm,"wb")) == NULL) + { + /* Failure to open the output file may be + simply due to an insufficiant permission setting. */ + fprintf(stderr,"Output file %s cannot be opened. Enter new file name: ", Flnm); + if (fgets(Flnm,MAX_FILE_NAME_SIZE,stdin) == NULL) exit(1); + + if (Flnm[strlen(Flnm) - 1] == '\n') Flnm[strlen(Flnm) - 1] = '\0'; + } + +#ifdef USE_FILE_BUFFERS + FiloutBuf = (char *) NoFailMalloc (BUFFSZ); + setvbuf(Filout, FiloutBuf, _IOFBF, BUFFSZ); +#endif + +} /* procedure OPENFILOUT */ + +void GetLine(char* str,FILE *in) +{ + char *result; + + result = fgets(str,MAX_LINE_SIZE,in); + if ((result == NULL) && !feof (in)) fprintf(stderr,"Error occurred while reading from file\n"); +} + +// 0 or 1 +int GetBin(const char *str) +{ + int result; + unsigned int value; + + result = sscanf(str,"%u",&value); + + if (result == 1) return value & 1; + else + { + fprintf(stderr,"GetBin: some error occurred when parsing options.\n"); + exit (1); + } +} + +int GetDec(const char *str) +{ + int result; + unsigned int value; + + result = sscanf(str,"%u",&value); + + if (result == 1) return value; + else + { + fprintf(stderr,"GetDec: some error occurred when parsing options.\n"); + exit (1); + } +} + +int GetHex(const char *str) +{ + int result; + unsigned int value; + + result = sscanf(str,"%x",&value); + + if (result == 1) return value; + else + { + fprintf(stderr,"GetHex: some error occurred when parsing options.\n"); + exit (1); + } +} + +// Char t/T: true f/F: false +bool GetBoolean(const char *str) +{ + int result; + unsigned char value, temp; + + result = sscanf(str,"%c",&value); + temp = tolower(value); + + if ((result == 1) && ((temp == 't') || (temp == 'f'))) + { + return (temp == 't'); + } + else + { + fprintf(stderr,"GetBoolean: some error occurred when parsing options.\n"); + exit (1); + } +} + +void GetExtension(const char *str,char *ext) +{ + if (strlen(str) > MAX_EXTENSION_SIZE) + usage(); + + strcpy(ext, str); +} + +/* Adds an extension to a file name */ +void PutExtension(char *Flnm, char *Extension) +{ + char *Period; /* location of period in file name */ + bool Samename; + + /* This assumes DOS like file names */ + /* Don't use strchr(): consider the following filename: + ../my.dir/file.hex + */ + if ((Period = strrchr(Flnm,'.')) != NULL) + *(Period) = '\0'; + + Samename = false; + if (strcmp(Extension, Period+1) == 0) + Samename = true; + + strcat(Flnm,"."); + strcat(Flnm, Extension); + if (Samename) + { + fprintf (stderr,"Input and output filenames (%s) are the same.", Flnm); + exit(1); + } +} + +void VerifyChecksumValue(void) +{ + if ((Checksum != 0) && Enable_Checksum_Error) + { + fprintf(stderr,"Checksum error in record %d: should be %02X\n", + Record_Nb, (256 - Checksum) & 0xFF); + Status_Checksum_Error = true; + } +} + +void CrcParamsCheck(void) +{ + switch (Cks_Type) + { + case CRC8: + Crc_Poly &= 0xFF; + Crc_Init &= 0xFF; + Crc_XorOut &= 0xFF; + break; + case CRC16: + Crc_Poly &= 0xFFFF; + Crc_Init &= 0xFFFF; + Crc_XorOut &= 0xFFFF; + break; + case CRC32: + break; + default: + fprintf (stderr,"See file CRC list.txt for parameters\n"); + exit(1); + } +} + +void WriteMemBlock16(uint16_t Value) +{ + if (Endian == 1) + { + Memory_Block[Cks_Addr - Lowest_Address] = u16_hi(Value); + Memory_Block[Cks_Addr - Lowest_Address +1] = u16_lo(Value); + } + else + { + Memory_Block[Cks_Addr - Lowest_Address +1] = u16_hi(Value); + Memory_Block[Cks_Addr - Lowest_Address] = u16_lo(Value); + } +} + +void WriteMemBlock32(uint32_t Value) +{ + if (Endian == 1) + { + Memory_Block[Cks_Addr - Lowest_Address] = u32_b3(Value); + Memory_Block[Cks_Addr - Lowest_Address +1] = u32_b2(Value); + Memory_Block[Cks_Addr - Lowest_Address +2] = u32_b1(Value); + Memory_Block[Cks_Addr - Lowest_Address +3] = u32_b0(Value); + } + else + { + Memory_Block[Cks_Addr - Lowest_Address +3] = u32_b3(Value); + Memory_Block[Cks_Addr - Lowest_Address +2] = u32_b2(Value); + Memory_Block[Cks_Addr - Lowest_Address +1] = u32_b1(Value); + Memory_Block[Cks_Addr - Lowest_Address] = u32_b0(Value); + } +} + +void WriteMemory(void) +{ + if ((Cks_Addr >= Lowest_Address) || (Cks_Addr < Highest_Address)) + { + if(Force_Value) + { + switch (Cks_Type) + { + case 0: + Memory_Block[Cks_Addr - Lowest_Address] = Cks_Value; + fprintf(stdout,"Addr %08X set to %02X\n",Cks_Addr, Cks_Value); + break; + case 1: + WriteMemBlock16(Cks_Value); + fprintf(stdout,"Addr %08X set to %04X\n",Cks_Addr, Cks_Value); + break; + case 2: + WriteMemBlock32(Cks_Value); + fprintf(stdout,"Addr %08X set to %08X\n",Cks_Addr, Cks_Value); + break; + default:; + } + } + else if (Cks_Addr_set) + { + /* Add a checksum to the binary file */ + if (!Cks_range_set) + { + Cks_Start = Lowest_Address; + Cks_End = Highest_Address; + } + /* checksum range MUST BE in the array bounds */ + + if (Cks_Start < Lowest_Address) + { + fprintf(stdout,"Modifying range start from %X to %X\n",Cks_Start,Lowest_Address); + Cks_Start = Lowest_Address; + } + if (Cks_End > Highest_Address) + { + fprintf(stdout,"Modifying range end from %X to %X\n",Cks_End,Highest_Address); + Cks_End = Highest_Address; + } + + switch (Cks_Type) + { + case CHK8_SUM: + { + uint8_t wCKS = 0; + + for (unsigned int i=Cks_Start; i<=Cks_End; i++) + { + wCKS += Memory_Block[i - Lowest_Address]; + } + + fprintf(stdout,"8-bit Checksum = %02X\n",wCKS & 0xff); + Memory_Block[Cks_Addr - Lowest_Address] = wCKS; + fprintf(stdout,"Addr %08X set to %02X\n",Cks_Addr, wCKS); + } + break; + + case CHK16: + { + uint16_t wCKS, w; + + wCKS = 0; + + if (Endian == 1) + { + for (unsigned int i=Cks_Start; i<=Cks_End; i+=2) + { + w = Memory_Block[i - Lowest_Address +1] | ((word)Memory_Block[i - Lowest_Address] << 8); + wCKS += w; + } + } + else + { + for (unsigned int i=Cks_Start; i<=Cks_End; i+=2) + { + w = Memory_Block[i - Lowest_Address] | ((word)Memory_Block[i - Lowest_Address +1] << 8); + wCKS += w; + } + } + fprintf(stdout,"16-bit Checksum = %04X\n",wCKS); + WriteMemBlock16(wCKS); + fprintf(stdout,"Addr %08X set to %04X\n",Cks_Addr, wCKS); + } + break; + + case CRC8: + { + uint8_t CRC8; + crc_table = NoFailMalloc(256); + + if (Crc_RefIn) + { + init_crc8_reflected_tab(Reflect8[Crc_Poly]); + CRC8 = Reflect8[Crc_Init]; + } + else + { + init_crc8_normal_tab(Crc_Poly); + CRC8 = Crc_Init; + } + + for (unsigned int i=Cks_Start; i<=Cks_End; i++) + { + CRC8 = update_crc8(CRC8,Memory_Block[i - Lowest_Address]); + } + + CRC8 = (CRC8 ^ Crc_XorOut) & 0xff; + Memory_Block[Cks_Addr - Lowest_Address] = CRC8; + fprintf(stdout,"Addr %08X set to %02X\n",Cks_Addr, CRC8); + } + break; + + case CRC16: + { + uint16_t CRC16; + crc_table = NoFailMalloc(256 * 2); + + if (Crc_RefIn) + { + init_crc16_reflected_tab(Reflect16(Crc_Poly)); + CRC16 = Reflect16(Crc_Init); + + for (unsigned int i=Cks_Start; i<=Cks_End; i++) + { + CRC16 = update_crc16_reflected(CRC16,Memory_Block[i - Lowest_Address]); + } + } + else + { + init_crc16_normal_tab(Crc_Poly); + CRC16 = Crc_Init; + + + for (unsigned int i=Cks_Start; i<=Cks_End; i++) + { + CRC16 = update_crc16_normal(CRC16,Memory_Block[i - Lowest_Address]); + } + } + + CRC16 = (CRC16 ^ Crc_XorOut) & 0xffff; + WriteMemBlock16(CRC16); + fprintf(stdout,"Addr %08X set to %04X\n",Cks_Addr, CRC16); + } + break; + + case CRC32: + { + uint32_t CRC32; + + crc_table = NoFailMalloc(256 * 4); + if (Crc_RefIn) + { + init_crc32_reflected_tab(Reflect32(Crc_Poly)); + CRC32 = Reflect32(Crc_Init); + + for (unsigned int i=Cks_Start; i<=Cks_End; i++) + { + CRC32 = update_crc32_reflected(CRC32,Memory_Block[i - Lowest_Address]); + } + } + else + { + init_crc32_normal_tab(Crc_Poly); + CRC32 = Crc_Init; + + for (unsigned int i=Cks_Start; i<=Cks_End; i++) + { + CRC32 = update_crc32_normal(CRC32,Memory_Block[i - Lowest_Address]); + } + } + + CRC32 ^= Crc_XorOut; + WriteMemBlock32(CRC32); + fprintf(stdout,"Addr %08X set to %08X\n",Cks_Addr, CRC32); + } + break; + + default: + ; + } + + free(crc_table); + } + } + else + { + fprintf (stderr,"Force/Check address outside of memory range\n"); + } + + /* write binary file */ + fwrite (Memory_Block, + Max_Length, + 1, + Filout); + + free (Memory_Block); + + // Minimum_Block_Size is set; the memory buffer is multiple of this? + if (Minimum_Block_Size_Setted==true) + { + Module = Max_Length % Minimum_Block_Size; + if (Module) + { + Memory_Block = (byte *) NoFailMalloc(Module); + memset (Memory_Block,Pad_Byte,Module); + fwrite (Memory_Block, + Module, + 1, + Filout); + free (Memory_Block); + if (Max_Length_Setted==true) + fprintf(stdout,"Attention Max Length changed by Minimum Block Size\n"); + } + } +} diff --git a/tools/hex2bin-2.0/src/common.h b/tools/hex2bin-2.0/src/common.h new file mode 100644 index 0000000..64caff5 --- /dev/null +++ b/tools/hex2bin-2.0/src/common.h @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include + +#include "binary.h" +#include "libcrc.h" + +/* To compile with Microsoft Visual Studio */ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif + +#if defined(MSDOS) || defined(__DOS__) || defined(__MSDOS__) || defined(_MSDOS) +#define _IS_OPTION_(x) (((x) == '-') || ((x) == '/')) +#else +/* Assume unix and similar */ +/* We don't accept an option beginning with a '/' because it could be a file name. */ +#define _IS_OPTION_(x) ((x) == '-') +#endif + +/* We use buffer to speed disk access. */ +#ifdef USE_FILE_BUFFERS +#define BUFFSZ 4096 +#endif + +/* FIXME how to get it from the system/OS? */ +#define MAX_FILE_NAME_SIZE 81 + +#ifdef DOS +#define MAX_EXTENSION_SIZE 4 +#else +#define MAX_EXTENSION_SIZE 16 +#endif + +/* The data records can contain 255 bytes: this means 512 characters. */ +#define MAX_LINE_SIZE 1024 + +typedef char filetype[MAX_FILE_NAME_SIZE]; +typedef unsigned char byte; +typedef unsigned short word; + +#define LAST_CHECK_METHOD 4 + +typedef enum Crc +{ + CHK8_SUM =0, + CHK16, + CRC8, + CRC16, + CRC32 +} t_CRC; + +extern const char *Pgm_Name; +void usage(void); +void DisplayCheckMethods(void); + +void *NoFailMalloc (size_t size); +void NoFailOpenInputFile (char *Flnm); +void NoFailOpenOutputFile (char *Flnm); +void GetLine(char* str,FILE *in); +int GetBin(const char *str); +int GetDec(const char *str); +int GetHex(const char *str); +bool GetBoolean(const char *str); +void GetExtension(const char *str,char *ext); +void PutExtension(char *Flnm, char *Extension); + +filetype Filename; /* string for opening files */ +char Extension[MAX_EXTENSION_SIZE]; /* filename extension for output files */ + +FILE *Filin, /* input files */ + *Filout; /* output files */ + +#ifdef USE_FILE_BUFFERS +char *FilinBuf, /* text buffer for file input */ + *FiloutBuf; /* text buffer for file output */ +#endif + +int Pad_Byte; +bool Enable_Checksum_Error; +bool Status_Checksum_Error; +byte Checksum; +unsigned int Record_Nb; + +/* This will hold binary codes translated from hex file. */ +byte *Memory_Block; +unsigned int Lowest_Address, Highest_Address; +unsigned int Starting_Address; +unsigned int Max_Length; +unsigned int Minimum_Block_Size; +int Module; +bool Minimum_Block_Size_Setted; +bool Starting_Address_Setted; +bool Max_Length_Setted; +bool Swap_Wordwise; + +int Endian; + +t_CRC Cks_Type; +unsigned int Cks_Start, Cks_End, Cks_Addr, Cks_Value; +bool Cks_range_set; +bool Cks_Addr_set; +bool Force_Value; + +unsigned int Crc_Poly, Crc_Init, Crc_XorOut; +bool Crc_RefIn; +bool Crc_RefOut; + +void VerifyChecksumValue(void); +void CrcParamsCheck(void); +void WriteMemBlock16(uint16_t Value); +void WriteMemBlock32(uint32_t Value); +void WriteMemory(void); + diff --git a/tools/hex2bin-2.0/src/hex2bin.1 b/tools/hex2bin-2.0/src/hex2bin.1 new file mode 100644 index 0000000..c2e5e89 --- /dev/null +++ b/tools/hex2bin-2.0/src/hex2bin.1 @@ -0,0 +1,294 @@ +.\" Automatically generated by Pod::Man 2.27 (Pod::Simple 3.28) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +. ds C` +. ds C' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.\" +.\" Avoid warning from groff about undefined register 'F'. +.de IX +.. +.nr rF 0 +.if \n(.g .if rF .nr rF 1 +.if (\n(rF:(\n(.g==0)) \{ +. if \nF \{ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. if !\nF==2 \{ +. nr % 0 +. nr F 2 +. \} +. \} +.\} +.rr rF +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "HEX2BIN 1" +.TH HEX2BIN 1 "2015-02-28" "perl v5.18.2" "User Contributed Perl Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +hex2bin/mot2bin \e\- converts Intel/Motorola hex files into binary +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +hex2bin [options] file +.PP +Option list: + [\-c] + [\-C Poly Init RefIn RefOut XorOut] + [\-e extension] + [\-E 0|1] + [\-f address] + [\-F address value] + [\-k checksum type] + [\-l length] + [\-m minimum block size] + [\-p pad byte] + [\-r start end] + [\-s address] + [\-w] +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\fBHex2bin\fR +is a program that converts an Intel hex format into binary. +It can handle the extended Intel hex format. Both the segmented +and linear address records are supported. +Records need not be sorted and there can be gaps between records. +Records are assumed to be non-overlapping. +Padding bytes may be specified and a checksum may be inserted in the +binary file. +.PP +\&\fBMot2bin\fR +does the same with Motorola hex files. It has the same features and command line +options. 24 bit and 32 bit records are supported. +.SH "OPTIONS" +.IX Header "OPTIONS" +Options can be specified in any order, with the file name at the end. Options are +now case sensitive. All option values are specified in hexadecimal. +.PP +\&\fB\-c\fR +.PP +Enables checksum verification. +.PP +By default, it ignores checksum errors in the hex file, so that someone can change +by hand some bytes with a text editor, allowing quick fixes without recompiling a source +code all over again. This is useful when tweaking constants directly in the code or +something similar. If you want checksum error reporting, specify the option \-c. +.PP +\&\fBEx.: hex2bin \-c example.hex\fR +.PP +If there is a checksum error somewhere, the program will continue the +conversion anyway. +.PP +\&\fB\-C Poly Init RefIn RefOut XorOut\fR +.PP +\&\s-1CRC\s0 parameters. See the doc/CRC list.txt file for a description of common CRCs. See also +the test/Makefile for examples of command lines. Needs \fB\-k\fR and \fB\-f\fR option. +RefIn and RefOut parameters are specified by \fBt\fR or \fBf\fR for true or false. +.PP +\&\fB\-d\fR +.PP +Display the list of available check methods and sizes. +.PP +\&\fB\-e extension\fR +.PP +By default, the output file will have an extension \fBfilename.bin\fR. +Another extension may be specified with this command: +.PP +\&\fBEx.: hex2bin \-e com example.hex\fR +.PP +The output file will be example.com +.PP +\&\fB\-E 0|1\fR +.PP +Endianness for writing the check result or forcing a 16\-bit value. + \fB0\fR: little, \fB1\fR: big. +.PP +By default, little endian is used. +.PP +\&\fB\-f address\fR +.PP +Address in hexadecimal for inserting the check value in the binary file. Needs \fB\-k\fR +option to specify the check method. A range can be specified with option \fB\-r\fR. +.PP +\&\fB\-F address value\fR +.PP +Address and value of checksum to insert (force) in the binary file. Needs \fB\-k\fR +option to specify the size. The value is written as is. +.PP +\&\fB\-k 0\-4\fR +.PP +In many cases, someone needs to insert a check value in the binary file. For example, +a boot rom is programmed with a checksum which is verified at power-up. This feature +uses also options \fB\-r\fR, \fB\-C\fR and \fB\-f\fR. Display the list with \fB\-d\fR. +.PP +Select the checksum type to insert into the binary file + 0: Checksum 8\-bit + 1: Checksum 16\-bit + 2: \s-1CRC8 + 3: CRC16 + 4: CRC32\s0 +.PP +\&\fB\-l length\fR +.PP +The binary file will be padded with \s-1FF\s0 or pad bytes as specified by the option +below, up to a maximal Length (Starting address + Length \-1 is Max Address) +.PP +\&\fB\-m minimum_block_size\fR +.PP +File Size Dimension will be a multiple of Minimum block size. +File will be filled with Pattern. +Length must be a power of 2 in hexadecimal [see \fB\-l\fR option] +Attention this option is \s-1STRONGER\s0 than Maximal Length +.PP +\&\fB\-p pad_byte\fR +.PP +Pads unused locations with the specified byte. +.PP +By default, this byte is \s-1FF,\s0 which is the unprogrammed value for most EPROM/EEPROM/Flash. +.PP +\&\fBEx.: hex2bin \-p 3E example.hex\fR +.PP +\&\fB\-r [start] [end]\fR +.PP +Range to compute binary checksum over (default is min and max addresses) +.PP +\&\fB\-s address\fR +.PP +Specify the starting address of the binary file. +.PP +Normally, hex2bin will generate a binary file starting at the lowest address in +the hex file. If the lowest address isn't 0000, ex: 0100, the first byte that +should be at 0100 will be stored at address 0000 in the binary file. This may +cause problems when using the binary file to program an \s-1EPROM.\s0 +.PP +If you can't specify the starting address (or offset) to your \s-1EPROM\s0 programmer, +you can specify a starting address on the command line: +.PP +\&\fBEx.: hex2bin \-s 0000 records_start_at_0100.hex\fR +.PP +The bytes will be stored in the binary file with a padding from 0000 to the +lowest address (00FF in this case). Padding bytes are all \s-1FF\s0 by default so an \s-1EPROM\s0 +programmer can skip these bytes when programming. The padding value can be changed +with the \-p option. +.PP +\&\fB\-w\fR +.PP +Swap wordwise (low <\-> high). Used by Microchip's \s-1MPLAB IDE\s0 +.SH "NOTES" +.IX Header "NOTES" +This program does minimal error checking since many hex files are +generated by known good assemblers. +.SH "AUTHOR Jacques Pelletier (jpelletier@ieee.org) \- version 2.0" +.IX Header "AUTHOR Jacques Pelletier (jpelletier@ieee.org) - version 2.0" diff --git a/tools/hex2bin-2.0/src/hex2bin.c b/tools/hex2bin-2.0/src/hex2bin.c new file mode 100644 index 0000000..7537d8c --- /dev/null +++ b/tools/hex2bin-2.0/src/hex2bin.c @@ -0,0 +1,587 @@ +/* + hex2bin converts an Intel hex file to binary. + + Copyright (C) 2015, Jacques Pelletier + checksum extensions Copyright (C) 2004 Rockwell Automation + 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. + 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. + + 20040617 Alf Lacis: Added pad byte (may not always want FF). + Added 'break;' to remove GNU compiler warning about label at + end of compound statement + Added PROGRAM & VERSION strings. + + 20071005 PG: Improvements on options parsing + 20091212 JP: Corrected crash on 0 byte length data records + 20100402 JP: Corrected bug on physical address calculation for extended + linear address record. + ADDRESS_MASK is now calculated from MEMORY_SIZE + + 20120125 Danny Schneider: + Added code for filling a binary file to a given Max_Length relative to + Starting Address if Max-Address is larger than Highest-Address + 20120509 Yoshimasa Nakane: + modified error checking (also for output file, JP) + 20141005 JP: added support for byte swapped hex files + corrected bug caused by extra LF at end or within file + 20141008 JP: removed junk code + 20141121 Slucx: added line for removing extra CR when entering file name at run time. + 20141122 Simone Fratini: small feature added + 20150116 Richard Genoud (Paratronic): correct buffer overflows/wrong results with the -l flag + 20150122 JP: added support for different check methods + 20150221 JP: rewrite of the checksum write/force value +*/ + +#define PROGRAM "hex2bin" +#define VERSION "2.0" + +#include "common.h" + +#define NO_ADDRESS_TYPE_SELECTED 0 +#define LINEAR_ADDRESS 1 +#define SEGMENTED_ADDRESS 2 + +const char *Pgm_Name = PROGRAM; + +int main (int argc, char *argv[]) +{ + /* line inputted from file */ + char Line[MAX_LINE_SIZE]; + + /* flag that a file was read */ + bool Fileread; + + /* cmd-line parameter # */ + char *p; + + int Param,result; + + /* Application specific */ + + unsigned int Nb_Bytes; + unsigned int First_Word, Address, Segment, Upper_Address; + unsigned int Phys_Addr, Type; + unsigned int temp; + unsigned int Records_Start; // Lowest address of the records + + /* We will assume that when one type of addressing is selected, it will be valid for all the + current file. Records for the other type will be ignored. */ + unsigned int Seg_Lin_Select = NO_ADDRESS_TYPE_SELECTED; + + unsigned int temp2; + + byte Data_Str[MAX_LINE_SIZE]; + + fprintf (stdout,PROGRAM" v"VERSION", Copyright (C) 2015 Jacques Pelletier & contributors\n\n"); + + if (argc == 1) + usage(); + + strcpy(Extension, "bin"); /* default is for binary file extension */ + + /* read file */ + Starting_Address = 0; + + /* + use p for parsing arguments + use i for number of parameters to skip + use c for the current option + */ + for (Param = 1; Param < argc; Param++) + { + int i = 0; + char c; + + p = argv[Param]; + c = *(p+1); /* Get option character */ + + if ( _IS_OPTION_(*p) ) + { + // test for no space between option and parameter + if (strlen(p) != 2) usage(); + + switch(c) + { + /* file extension */ + case 'c': + Enable_Checksum_Error = true; + i = 0; + break; + case 'd': + DisplayCheckMethods(); + case 'e': + GetExtension(argv[Param + 1],Extension); + i = 1; /* add 1 to Param */ + break; + case 'E': + Endian = GetBin(argv[Param + 1]); + i = 1; /* add 1 to Param */ + break; + case 'f': + Cks_Addr = GetHex(argv[Param + 1]); + Cks_Addr_set = true; + i = 1; /* add 1 to Param */ + break; + case 'F': + Cks_Addr = GetHex(argv[Param + 1]); + Cks_Value = GetHex(argv[Param + 2]); + Force_Value = true; + i = 2; /* add 2 to Param */ + break; + case 'k': + Cks_Type = GetHex(argv[Param + 1]); + { + if (Cks_Type > LAST_CHECK_METHOD) usage(); + } + i = 1; /* add 1 to Param */ + break; + case 'l': + Max_Length = GetHex(argv[Param + 1]); + if (Max_Length > 0x800000) + { + fprintf(stderr,"Max_Length = %u\n", Max_Length); + exit(1); + } + Max_Length_Setted = true; + i = 1; /* add 1 to Param */ + break; + case 'm': + Minimum_Block_Size = GetHex(argv[Param + 1]); + Minimum_Block_Size_Setted = true; + i = 1; /* add 1 to Param */ + break; + case 'p': + Pad_Byte = GetHex(argv[Param + 1]); + i = 1; /* add 1 to Param */ + break; + case 'r': + Cks_Start = GetHex(argv[Param + 1]); + Cks_End = GetHex(argv[Param + 2]); + Cks_range_set = true; + i = 2; /* add 2 to Param */ + break; + case 's': + Starting_Address = GetHex(argv[Param + 1]); + Starting_Address_Setted = true; + i = 1; /* add 1 to Param */ + break; + case 'w': + Swap_Wordwise = true; + i = 0; + break; + case 'C': + Crc_Poly = GetHex(argv[Param + 1]); + Crc_Init = GetHex(argv[Param + 2]); + Crc_RefIn = GetBoolean(argv[Param + 3]); + Crc_RefOut = GetBoolean(argv[Param + 4]); + Crc_XorOut = GetHex(argv[Param + 5]); + CrcParamsCheck(); + i = 5; /* add 5 to Param */ + break; + + case '?': + case 'h': + default: + usage(); + } /* switch */ + + /* Last parameter is not a filename */ + if (Param == argc-1) usage(); + + /* if (Param + i) < (argc -1) */ + if (Param < argc -1 -i) Param += i; + else usage(); + + } + else + break; + /* if option */ + } /* for Param */ + + /* when user enters input file name */ + + /* Assume last parameter is filename */ + strcpy(Filename,argv[argc -1]); + + /* Just a normal file name */ + NoFailOpenInputFile (Filename); + PutExtension(Filename, Extension); + NoFailOpenOutputFile(Filename); + Fileread = true; + + /* To begin, assume the lowest address is at the end of the memory. + While reading each records, subsequent addresses will lower this number. + At the end of the input file, this value will be the lowest address. + + A similar assumption is made for highest address. It starts at the + beginning of memory. While reading each records, subsequent addresses will raise this number. + At the end of the input file, this value will be the highest address. */ + Lowest_Address = (unsigned int)-1; + Highest_Address = 0; + Records_Start = 0; + Segment = 0; + Upper_Address = 0; + Record_Nb = 0; // Used for reporting errors + + /* get highest and lowest addresses so that we can allocate the right size */ + do + { + unsigned int i; + + /* Read a line from input file. */ + GetLine(Line,Filin); + Record_Nb++; + + /* Remove carriage return/line feed at the end of line. */ + i = strlen(Line); + + if (--i != 0) + { + if (Line[i] == '\n') Line[i] = '\0'; + + /* Scan the first two bytes and nb of bytes. + The two bytes are read in First_Word since its use depend on the + record type: if it's an extended address record or a data record. + */ + result = sscanf (Line, ":%2x%4x%2x%s",&Nb_Bytes,&First_Word,&Type,Data_Str); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + p = (char *) Data_Str; + + /* If we're reading the last record, ignore it. */ + switch (Type) + { + /* Data record */ + case 0: + if (Nb_Bytes == 0) + break; + + Address = First_Word; + + if (Seg_Lin_Select == SEGMENTED_ADDRESS) + { + Phys_Addr = (Segment << 4) + Address; + } + else + { + /* LINEAR_ADDRESS or NO_ADDRESS_TYPE_SELECTED + Upper_Address = 0 as specified in the Intel spec. until an extended address + record is read. */ + Phys_Addr = ((Upper_Address << 16) + Address); + } + + /* Set the lowest address as base pointer. */ + if (Phys_Addr < Lowest_Address) + Lowest_Address = Phys_Addr; + + /* Same for the top address. */ + temp = Phys_Addr + Nb_Bytes -1; + + if (temp > Highest_Address) + Highest_Address = temp; + + break; + + case 2: + /* First_Word contains the offset. It's supposed to be 0000 so + we ignore it. */ + + /* First extended segment address record ? */ + if (Seg_Lin_Select == NO_ADDRESS_TYPE_SELECTED) + Seg_Lin_Select = SEGMENTED_ADDRESS; + + /* Then ignore subsequent extended linear address records */ + if (Seg_Lin_Select == SEGMENTED_ADDRESS) + { + result = sscanf (p, "%4x%2x",&Segment,&temp2); + if (result != 2) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + /* Update the current address. */ + Phys_Addr = (Segment << 4); + } + else + { + fprintf(stderr,"Ignored extended linear address record %d\n", Record_Nb); + } + break; + + case 4: + /* First_Word contains the offset. It's supposed to be 0000 so + we ignore it. */ + + /* First extended linear address record ? */ + if (Seg_Lin_Select == NO_ADDRESS_TYPE_SELECTED) + Seg_Lin_Select = LINEAR_ADDRESS; + + /* Then ignore subsequent extended segment address records */ + if (Seg_Lin_Select == LINEAR_ADDRESS) + { + result = sscanf (p, "%4x%2x",&Upper_Address,&temp2); + if (result != 2) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + /* Update the current address. */ + Phys_Addr = (Upper_Address << 16); + } + else + { + fprintf(stderr,"Ignored extended segment address record %d\n", Record_Nb); + } + break; + + default: + break; + } + } + } + while (!feof (Filin)); + + rewind(Filin); + Segment = 0; + Upper_Address = 0; + Record_Nb = 0; + + if (Starting_Address_Setted == true) + { + Records_Start = Lowest_Address; + Lowest_Address = Starting_Address; + } + else + { + Records_Start = Lowest_Address; + Starting_Address = Lowest_Address; + } + + if (Max_Length_Setted == false) + Max_Length = Highest_Address - Lowest_Address + 1; + else + Highest_Address = Lowest_Address + Max_Length - 1; + + /* Now, that we know the buffer size, we can allocate it. */ + /* allocate a buffer */ + Memory_Block = (byte *) NoFailMalloc(Max_Length); + + /* For EPROM or FLASH memory types, fill unused bytes with FF or the value specified by the p option */ + memset (Memory_Block,Pad_Byte,Max_Length); + + /* Read the file & process the lines. */ + do /* repeat until EOF(Filin) */ + { + unsigned int i; + + /* Read a line from input file. */ + GetLine(Line,Filin); + Record_Nb++; + + /* Remove carriage return/line feed at the end of line. */ + i = strlen(Line); + + //fprintf(stderr,"Record: %d; length: %d\n", Record_Nb, i); + + if (--i != 0) + { + if (Line[i] == '\n') Line[i] = '\0'; + + /* Scan the first two bytes and nb of bytes. + The two bytes are read in First_Word since its use depend on the + record type: if it's an extended address record or a data record. + */ + result = sscanf (Line, ":%2x%4x%2x%s",&Nb_Bytes,&First_Word,&Type,Data_Str); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + Checksum = Nb_Bytes + (First_Word >> 8) + (First_Word & 0xFF) + Type; + + p = (char *) Data_Str; + + /* If we're reading the last record, ignore it. */ + switch (Type) + { + /* Data record */ + case 0: + if (Nb_Bytes == 0) + { + fprintf(stderr,"0 byte length Data record ignored\n"); + break; + } + + Address = First_Word; + + if (Seg_Lin_Select == SEGMENTED_ADDRESS) + Phys_Addr = (Segment << 4) + Address; + else + /* LINEAR_ADDRESS or NO_ADDRESS_TYPE_SELECTED + Upper_Address = 0 as specified in the Intel spec. until an extended address + record is read. */ + Phys_Addr = ((Upper_Address << 16) + Address); + + /* Check that the physical address stays in the buffer's range. */ + if ((Phys_Addr >= Lowest_Address) && (Phys_Addr <= Highest_Address)) + { + /* The memory block begins at Lowest_Address */ + Phys_Addr -= Lowest_Address; + + /* Read the Data bytes. */ + /* Bytes are written in the Memory block even if checksum is wrong. */ + i = Nb_Bytes; + + do + { + result = sscanf (p, "%2x",&temp2); + if (result != 1) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + p += 2; + + /* Check that the physical address stays in the buffer's range. */ + if (Phys_Addr < Max_Length) + { + /* Overlapping record will erase the pad bytes */ + if (Swap_Wordwise) + { + if (Memory_Block[Phys_Addr ^ 1] != Pad_Byte) fprintf(stderr,"Overlapped record detected\n"); + Memory_Block[Phys_Addr++ ^ 1] = temp2; + } + else + { + if (Memory_Block[Phys_Addr] != Pad_Byte) fprintf(stderr,"Overlapped record detected\n"); + Memory_Block[Phys_Addr++] = temp2; + } + + Checksum = (Checksum + temp2) & 0xFF; + } + } + while (--i != 0); + + /* Read the Checksum value. */ + result = sscanf (p, "%2x",&temp2); + if (result != 1) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + /* Verify Checksum value. */ + Checksum = (Checksum + temp2) & 0xFF; + VerifyChecksumValue(); + } + else + { + if (Seg_Lin_Select == SEGMENTED_ADDRESS) + fprintf(stderr,"Data record skipped at %4X:%4X\n",Segment,Address); + else + fprintf(stderr,"Data record skipped at %8X\n",Phys_Addr); + } + + break; + + /* End of file record */ + case 1: + /* Simply ignore checksum errors in this line. */ + break; + + /* Extended segment address record */ + case 2: + /* First_Word contains the offset. It's supposed to be 0000 so + we ignore it. */ + + /* First extended segment address record ? */ + if (Seg_Lin_Select == NO_ADDRESS_TYPE_SELECTED) + Seg_Lin_Select = SEGMENTED_ADDRESS; + + /* Then ignore subsequent extended linear address records */ + if (Seg_Lin_Select == SEGMENTED_ADDRESS) + { + result = sscanf (p, "%4x%2x",&Segment,&temp2); + if (result != 2) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + /* Update the current address. */ + Phys_Addr = (Segment << 4); + + /* Verify Checksum value. */ + Checksum = (Checksum + (Segment >> 8) + (Segment & 0xFF) + temp2) & 0xFF; + VerifyChecksumValue(); + } + break; + + /* Start segment address record */ + case 3: + /* Nothing to be done since it's for specifying the starting address for + execution of the binary code */ + break; + + /* Extended linear address record */ + case 4: + /* First_Word contains the offset. It's supposed to be 0000 so + we ignore it. */ + + /* First extended linear address record ? */ + if (Seg_Lin_Select == NO_ADDRESS_TYPE_SELECTED) + Seg_Lin_Select = LINEAR_ADDRESS; + + /* Then ignore subsequent extended segment address records */ + if (Seg_Lin_Select == LINEAR_ADDRESS) + { + result = sscanf (p, "%4x%2x",&Upper_Address,&temp2); + if (result != 2) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + /* Update the current address. */ + Phys_Addr = (Upper_Address << 16); + + /* Verify Checksum value. */ + Checksum = (Checksum + (Upper_Address >> 8) + (Upper_Address & 0xFF) + temp2) + & 0xFF; + VerifyChecksumValue(); + } + break; + + /* Start linear address record */ + case 5: + /* Nothing to be done since it's for specifying the starting address for + execution of the binary code */ + break; + default: + fprintf(stderr,"Unknown record type\n"); + break; + } + } + } + while (!feof (Filin)); + /*-----------------------------------------------------------------------------*/ + + fprintf(stdout,"Binary file start = %08X\n",Lowest_Address); + fprintf(stdout,"Records start = %08X\n",Records_Start); + fprintf(stdout,"Highest address = %08X\n",Highest_Address); + fprintf(stdout,"Pad Byte = %X\n", Pad_Byte); + + WriteMemory(); + +#ifdef USE_FILE_BUFFERS + free (FilinBuf); + free (FiloutBuf); +#endif + + fclose (Filin); + fclose (Filout); + + if (Status_Checksum_Error && Enable_Checksum_Error) + { + fprintf(stderr,"Checksum error detected.\n"); + return 1; + } + + if (!Fileread) + usage(); + return 0; +} diff --git a/tools/hex2bin-2.0/src/hex2bin.pod b/tools/hex2bin-2.0/src/hex2bin.pod new file mode 100644 index 0000000..a8eb238 --- /dev/null +++ b/tools/hex2bin-2.0/src/hex2bin.pod @@ -0,0 +1,161 @@ +HEX2BIN 1 "2015 february 22nd" "Hex2bin Version 2.0" +=head1 NAME + +hex2bin/mot2bin \- converts Intel/Motorola hex files into binary + +=head1 SYNOPSIS + +hex2bin [options] file + +Option list: + [-c] + [-C Poly Init RefIn RefOut XorOut] + [-e extension] + [-E 0|1] + [-f address] + [-F address value] + [-k checksum type] + [-l length] + [-m minimum block size] + [-p pad byte] + [-r start end] + [-s address] + [-w] + +=head1 DESCRIPTION + +B +is a program that converts an Intel hex format into binary. +It can handle the extended Intel hex format. Both the segmented +and linear address records are supported. +Records need not be sorted and there can be gaps between records. +Records are assumed to be non-overlapping. +Padding bytes may be specified and a checksum may be inserted in the +binary file. + +B +does the same with Motorola hex files. It has the same features and command line +options. 24 bit and 32 bit records are supported. + +=head1 OPTIONS + +Options can be specified in any order, with the file name at the end. Options are +now case sensitive. All option values are specified in hexadecimal. + +B<-c> + +Enables checksum verification. + +By default, it ignores checksum errors in the hex file, so that someone can change +by hand some bytes with a text editor, allowing quick fixes without recompiling a source +code all over again. This is useful when tweaking constants directly in the code or +something similar. If you want checksum error reporting, specify the option -c. + +B + +If there is a checksum error somewhere, the program will continue the +conversion anyway. + +B<-C Poly Init RefIn RefOut XorOut> + +CRC parameters. See the doc/CRC list.txt file for a description of common CRCs. See also +the test/Makefile for examples of command lines. Needs B<-k> and B<-f> option. +RefIn and RefOut parameters are specified by B or B for true or false. + +B<-d> + +Display the list of available check methods and sizes. + +B<-e extension> + +By default, the output file will have an extension B. +Another extension may be specified with this command: + +B + +The output file will be example.com + +B<-E 0|1> + +Endianness for writing the check result or forcing a 16-bit value. + B<0>: little, B<1>: big. + +By default, little endian is used. + +B<-f address> + +Address in hexadecimal for inserting the check value in the binary file. Needs B<-k> +option to specify the check method. A range can be specified with option B<-r>. + +B<-F address value> + +Address and value of checksum to insert (force) in the binary file. Needs B<-k> +option to specify the size. The value is written as is. + +B<-k 0-4> + +In many cases, someone needs to insert a check value in the binary file. For example, +a boot rom is programmed with a checksum which is verified at power-up. This feature +uses also options B<-r>, B<-C> and B<-f>. Display the list with B<-d>. + +Select the checksum type to insert into the binary file + 0: Checksum 8-bit + 1: Checksum 16-bit + 2: CRC8 + 3: CRC16 + 4: CRC32 + +B<-l length> + +The binary file will be padded with FF or pad bytes as specified by the option +below, up to a maximal Length (Starting address + Length -1 is Max Address) + +B<-m minimum_block_size> + +File Size Dimension will be a multiple of Minimum block size. +File will be filled with Pattern. +Length must be a power of 2 in hexadecimal [see B<-l> option] +Attention this option is STRONGER than Maximal Length + +B<-p pad_byte> + +Pads unused locations with the specified byte. + +By default, this byte is FF, which is the unprogrammed value for most EPROM/EEPROM/Flash. + +B + +B<-r [start] [end]> + +Range to compute binary checksum over (default is min and max addresses) + +B<-s address> + +Specify the starting address of the binary file. + +Normally, hex2bin will generate a binary file starting at the lowest address in +the hex file. If the lowest address isn't 0000, ex: 0100, the first byte that +should be at 0100 will be stored at address 0000 in the binary file. This may +cause problems when using the binary file to program an EPROM. + +If you can't specify the starting address (or offset) to your EPROM programmer, +you can specify a starting address on the command line: + +B + +The bytes will be stored in the binary file with a padding from 0000 to the +lowest address (00FF in this case). Padding bytes are all FF by default so an EPROM +programmer can skip these bytes when programming. The padding value can be changed +with the -p option. + +B<-w> + +Swap wordwise (low <-> high). Used by Microchip's MPLAB IDE + +=head1 NOTES + +This program does minimal error checking since many hex files are +generated by known good assemblers. + +=head1 AUTHOR +Jacques Pelletier (jpelletier@ieee.org) - version 2.0 diff --git a/tools/hex2bin-2.0/src/libcrc.c b/tools/hex2bin-2.0/src/libcrc.c new file mode 100644 index 0000000..02bcd4b --- /dev/null +++ b/tools/hex2bin-2.0/src/libcrc.c @@ -0,0 +1,204 @@ +/********************************************************************* + * * + * Library : lib_crc * + * File : lib_crc.c * + * Author : Lammert Bies 1999-2008 * + * E-mail : info@lammertbies.nl * + * Language : ANSI C * + * * + * * + * Description * + * =========== * + * * + * The file lib_crc.c contains the private and public func- * + * tions used for the calculation of CRC-16, CRC-CCITT and * + * CRC-32 cyclic redundancy values. * + * * + * * + * Dependencies * + * ============ * + * * + * libcrc.h CRC definitions and prototypes * + * * + ********************************************************************/ +#include + +#ifndef G_GUINT64_CONSTANT +#define G_GUINT64_CONSTANT(val) (val##UL) +#endif + +void *crc_table; + +/* private */ + +void init_crc8_normal_tab(uint8_t polynom) +{ + int i, j; + uint8_t crc; + uint8_t *p; + + p = (uint8_t *) crc_table; + + for (i=0; i<256; i++) + { + crc = (uint8_t) i; + + for (j=0; j<8; j++) + { + if (crc & 0x80) crc = (crc << 1) ^ polynom; + else crc <<= 1; + } + *p++ = crc; + } +} + +void init_crc8_reflected_tab(uint8_t polynom) +{ + int i, j; + uint8_t crc; + uint8_t *p; + + p = (uint8_t *) crc_table; + + for (i=0; i<256; i++) + { + crc = (uint8_t) i; + + for (j=0; j<8; j++) + { + if (crc & 0x01) crc = (crc >> 1) ^ polynom; + else crc >>= 1; + } + *p++ = crc; + } +} + +/* Common routines for calculations */ +void init_crc16_normal_tab(uint16_t polynom) +{ + int i, j; + uint16_t crc; + uint16_t *p; + + p = (uint16_t *) crc_table; + + for (i=0; i<256; i++) + { + crc = ((uint16_t) i) << 8; + + for (j=0; j<8; j++) + { + if ( crc & 0x8000 ) crc = ( crc << 1 ) ^ polynom; + else crc <<= 1; + } + *p++ = crc; + } +} + +void init_crc16_reflected_tab(uint16_t polynom) +{ + int i, j; + uint16_t crc; + uint16_t *p; + + p = (uint16_t *) crc_table; + + for (i=0; i<256; i++) + { + crc = (uint16_t) i; + + for (j=0; j<8; j++) + { + if ( crc & 0x0001 ) crc = ( crc >> 1 ) ^ polynom; + else crc >>= 1; + } + *p++ = crc; + } +} + +void init_crc32_normal_tab(uint32_t polynom) +{ + int i, j; + uint32_t crc; + uint32_t *p; + + p = (uint32_t *) crc_table; + + for (i=0; i<256; i++) + { + crc = ((uint32_t) i) << 24; + + for (j=0; j<8; j++) + { + if ( crc & 0x80000000L ) crc = ( crc << 1 ) ^ polynom; + else crc <<= 1; + } + *p++ = crc; + } +} + +void init_crc32_reflected_tab(uint32_t polynom) +{ + int i, j; + uint32_t crc; + uint32_t *p; + + p = (uint32_t *) crc_table; + + for (i=0; i<256; i++) + { + crc = (uint32_t) i; + + for (j=0; j<8; j++) + { + if ( crc & 0x00000001L ) crc = ( crc >> 1 ) ^ polynom; + else crc >>= 1; + } + *p++ = crc; + } +} + +/* Common routines for calculations */ + +uint8_t update_crc8(uint8_t crc, uint8_t c) +{ + return (((uint8_t *) crc_table)[crc ^ c]); +} + +uint16_t update_crc16_normal(uint16_t crc, char c ) +{ + uint16_t short_c; + + short_c = 0x00ff & (uint16_t) c; + + /* Normal form */ + return (crc << 8) ^ ((uint16_t *) crc_table)[(crc >> 8) ^ short_c]; +} + +uint16_t update_crc16_reflected(uint16_t crc, char c ) +{ + uint16_t short_c; + + short_c = 0x00ff & (uint16_t) c; + + /* Reflected form */ + return (crc >> 8) ^ ((uint16_t *) crc_table)[(crc ^ short_c) & 0xff]; +} + +uint32_t update_crc32_normal(uint32_t crc, char c ) +{ + uint32_t long_c; + + long_c = 0x000000ffL & (uint32_t) c; + + return (crc << 8) ^ ((uint32_t *) crc_table)[((crc >> 24) ^ long_c) & 0xff]; +} + +uint32_t update_crc32_reflected(uint32_t crc, char c ) +{ + uint32_t long_c; + + long_c = 0x000000ffL & (uint32_t) c; + + return (crc >> 8) ^ ((uint32_t *) crc_table)[(crc ^ long_c) & 0xff]; +} diff --git a/tools/hex2bin-2.0/src/libcrc.h b/tools/hex2bin-2.0/src/libcrc.h new file mode 100644 index 0000000..39f20d0 --- /dev/null +++ b/tools/hex2bin-2.0/src/libcrc.h @@ -0,0 +1,44 @@ + /******************************************************************** + * * + * Library : lib_crc * + * File : lib_crc.h * + * Author : Lammert Bies 1999-2008 * + * E-mail : info@lammertbies.nl * + * Language : ANSI C * + * * + * * + * Description * + * =========== * + * * + * The file lib_crc.h contains public definitions and proto- * + * types for the CRC functions present in lib_crc.c. * + * * + * * + * Dependencies * + * ============ * + * * + * none * + * * + * * + ********************************************************************/ +#ifndef _LIBCRC_H_ +#define _LIBCRC_H_ + +void *crc_table; + +void init_crc8_normal_tab(uint8_t polynom); +void init_crc8_reflected_tab(uint8_t polynom); + +void init_crc16_normal_tab(uint16_t polynom); +void init_crc16_reflected_tab(uint16_t polynom); +void init_crc32_normal_tab(uint32_t polynom); +void init_crc32_reflected_tab(uint32_t polynom); + +uint8_t update_crc8(uint8_t crc, uint8_t c); + +uint16_t update_crc16_normal(uint16_t crc, char c ); +uint16_t update_crc16_reflected(uint16_t crc, char c ); +uint32_t update_crc32_normal(uint32_t crc, char c ); +uint32_t update_crc32_reflected(uint32_t crc, char c ); + +#endif /* _LIBCRC_H_ */ diff --git a/tools/hex2bin-2.0/src/mot2bin.c b/tools/hex2bin-2.0/src/mot2bin.c new file mode 100644 index 0000000..9e0e23c --- /dev/null +++ b/tools/hex2bin-2.0/src/mot2bin.c @@ -0,0 +1,518 @@ +/* +mot2bin converts a Motorola hex file to binary. + +Copyright (C) 2015, Jacques Pelletier +checksum extensions Copyright (C) 2004 Rockwell Automation +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. +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. + +20040617 Alf Lacis: Added pad byte (may not always want FF). + Added initialisation to Checksum to remove GNU + compiler warning about possible uninitialised usage + Added 2x'break;' to remove GNU compiler warning about label at + end of compound statement + Added PROGRAM & VERSION strings. + +20071005 PG: Improvements on options parsing +20091212 JP: Corrected crash on 0 byte length data records +20100402 JP: ADDRESS_MASK is now calculated from MEMORY_SIZE + +20120125 Danny Schneider: + Added code for filling a binary file to a given Max_Length relative to + Starting Address if Max-Address is larger than Highest-Address +20120509 Yoshimasa Nakane: + modified error checking (also for output file, JP) +20141005 JP: added support for byte swapped hex files + corrected bug caused by extra LF at end or within file +20141121 Slucx: added line for removing extra CR when entering file name at run time. +20150116 Richard Genoud (Paratronic): correct buffer overflows/wrong results with the -l flag +20150122 JP: added support for different check methods +20150221 JP: rewrite of the checksum write/force value +*/ + +#define PROGRAM "mot2bin" +#define VERSION "2.0" + +#include "common.h" + +const char *Pgm_Name = PROGRAM; + +int main (int argc, char *argv[]) +{ + /* line inputted from file */ + char Line[MAX_LINE_SIZE]; + + /* flag that a file was read */ + bool Fileread; + + /* cmd-line parameter # */ + char *p; + + int Param, result; + + /* Application specific */ + + unsigned int Nb_Bytes; + unsigned int First_Word, Address; + + unsigned int Phys_Addr, Type; + unsigned int Exec_Address; + unsigned int temp; + unsigned int Record_Count, Record_Checksum; + unsigned int Records_Start; // Lowest address of the records + + unsigned int temp2; + + byte Data_Str[MAX_LINE_SIZE]; + + fprintf (stdout,PROGRAM" v"VERSION", Copyright (C) 2015 Jacques Pelletier & contributors\n\n"); + + if (argc == 1) + usage(); + + strcpy(Extension, "bin"); /* default is for binary file extension */ + + /* read file */ + Starting_Address = 0; + + /* + use p for parsing arguments + use i for number of parameters to skip + use c for the current option + */ + for (Param = 1; Param < argc; Param++) + { + int i = 0; + char c; + + p = argv[Param]; + c = *(p+1); /* Get option character */ + + if ( _IS_OPTION_(*p) ) + { + // test for no space between option and parameter + if (strlen(p) != 2) usage(); + + switch(c) + { + /* file extension */ + case 'c': + Enable_Checksum_Error = true; + i = 0; + break; + case 'd': + DisplayCheckMethods(); + case 'e': + GetExtension(argv[Param + 1],Extension); + i = 1; /* add 1 to Param */ + break; + case 'f': + Cks_Addr = GetHex(argv[Param + 1]); + Cks_Addr_set = true; + i = 1; /* add 1 to Param */ + break; + case 'F': + Cks_Addr = GetHex(argv[Param + 1]); + Cks_Value = GetHex(argv[Param + 2]); + Force_Value = true; + i = 2; /* add 2 to Param */ + break; + case 'k': + Cks_Type = GetHex(argv[Param + 1]); + { + if (Cks_Type > LAST_CHECK_METHOD) usage(); + } + i = 1; /* add 1 to Param */ + break; + case 'l': + Max_Length = GetHex(argv[Param + 1]); + Max_Length_Setted = true; + i = 1; /* add 1 to Param */ + break; + case 'm': + Minimum_Block_Size = GetHex(argv[Param + 1]); + Minimum_Block_Size_Setted = true; + i = 1; /* add 1 to Param */ + break; + case 'p': + Pad_Byte = GetHex(argv[Param + 1]); + i = 1; /* add 1 to Param */ + break; + case 'r': + Cks_Start = GetHex(argv[Param + 1]); + Cks_End = GetHex(argv[Param + 2]); + Cks_range_set = true; + i = 2; /* add 2 to Param */ + break; + case 's': + Starting_Address = GetHex(argv[Param + 1]); + Starting_Address_Setted = true; + i = 1; /* add 1 to Param */ + break; + case 'w': + Swap_Wordwise = true; + i = 0; + break; + case 'C': + Crc_Poly = GetHex(argv[Param + 1]); + Crc_Init = GetHex(argv[Param + 2]); + Crc_RefIn = GetBoolean(argv[Param + 3]); + Crc_RefOut = GetBoolean(argv[Param + 4]); + Crc_XorOut = GetHex(argv[Param + 5]); + CrcParamsCheck(); + i = 5; /* add 5 to Param */ + break; + + case '?': + case 'h': + default: + usage(); + } /* switch */ + + /* Last parameter is not a filename */ + if (Param == argc-1) usage(); + + // fprintf(stderr,"Param: %d, option: %c\n",Param,c); + + /* if (Param + i) < (argc -1) */ + if (Param < argc -1 -i) Param += i; + else usage(); + + } + else + break; + /* if option */ + } /* for Param */ + + /* when user enters input file name */ + + /* Assume last parameter is filename */ + strcpy(Filename,argv[argc -1]); + + /* Just a normal file name */ + NoFailOpenInputFile (Filename); + PutExtension(Filename, Extension); + NoFailOpenOutputFile(Filename); + Fileread = true; + + /* To begin, assume the lowest address is at the end of the memory. + While reading each records, subsequent addresses will lower this number. + At the end of the input file, this value will be the lowest address. + + A similar assumption is made for highest address. It starts at the + beginning of memory. While reading each records, subsequent addresses will raise this number. + At the end of the input file, this value will be the highest address. */ + Lowest_Address = (unsigned int)-1; + Highest_Address = 0; + Records_Start = 0; + Record_Nb = 0; + + /* get highest and lowest addresses so that we can allocate the right size */ + do + { + unsigned int i; + + /* Read a line from input file. */ + GetLine(Line,Filin); + Record_Nb++; + + /* Remove carriage return/line feed at the end of line. */ + i = strlen(Line); + + if (--i != 0) + { + if (Line[i] == '\n') Line[i] = '\0'; + + p = (char *) Data_Str; + + switch(Line[1]) + { + case '0': + break; + + /* 16 bits address */ + case '1': + result = sscanf (Line,"S%1x%2x%4x",&Type,&Nb_Bytes,&First_Word); + if (result != 3) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + /* Adjust Nb_Bytes for the number of data bytes */ + Nb_Bytes = Nb_Bytes - 3; + break; + + /* 24 bits address */ + case '2': + result = sscanf (Line,"S%1x%2x%6x",&Type,&Nb_Bytes,&First_Word); + if (result != 3) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + /* Adjust Nb_Bytes for the number of data bytes */ + Nb_Bytes = Nb_Bytes - 4; + break; + + /* 32 bits address */ + case '3': + result = sscanf (Line,"S%1x%2x%8x",&Type,&Nb_Bytes,&First_Word); + if (result != 3) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + /* Adjust Nb_Bytes for the number of data bytes */ + Nb_Bytes = Nb_Bytes - 5; + break; + } + + Phys_Addr = First_Word; + + /* Set the lowest address as base pointer. */ + if (Phys_Addr < Lowest_Address) + Lowest_Address = Phys_Addr; + + /* Same for the top address. */ + temp = Phys_Addr + Nb_Bytes -1; + + if (temp > Highest_Address) + Highest_Address = temp; + } + } + while (!feof (Filin)); + + if (Starting_Address_Setted == true) + { + Records_Start = Lowest_Address; + Lowest_Address = Starting_Address; + } + else + { + Records_Start = Lowest_Address; + Starting_Address = Lowest_Address; + } + + if (Max_Length_Setted == false) + Max_Length = Highest_Address - Lowest_Address + 1; + else + Highest_Address = Lowest_Address + Max_Length - 1; + + /* Now, that we know the buffer size, we can allocate it. */ + /* allocate a buffer */ + Memory_Block = (byte *) NoFailMalloc(Max_Length); + + /* For EPROM or FLASH memory types, fill unused bytes with FF or the value specified by the p option */ + memset (Memory_Block,Pad_Byte,Max_Length); + + rewind(Filin); + Record_Nb = 0; + + /* Read the file & process the lines. */ + do /* repeat until EOF(Filin) */ + { + int i; + + Checksum = 0; + + /* Read a line from input file. */ + GetLine(Line,Filin); + Record_Nb++; + + /* Remove carriage return/line feed at the end of line. */ + i = strlen(Line); + + if (--i != 0) + { + if (Line[i] == '\n') Line[i] = '\0'; + + /* Scan starting address and nb of bytes. */ + /* Look at the record type after the 'S' */ + Type = 0; + + switch(Line[1]) + { + case '0': + result = sscanf (Line,"S0%2x0000484452%2x",&Nb_Bytes,&Record_Checksum); + if (result != 2) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + Checksum = Nb_Bytes + 0x48 + 0x44 + 0x52; + + /* Adjust Nb_Bytes for the number of data bytes */ + Nb_Bytes = 0; + break; + + /* 16 bits address */ + case '1': + result = sscanf (Line,"S%1x%2x%4x%s",&Type,&Nb_Bytes,&Address,Data_Str); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + Checksum = Nb_Bytes + (Address >> 8) + (Address & 0xFF); + + /* Adjust Nb_Bytes for the number of data bytes */ + Nb_Bytes = Nb_Bytes - 3; + break; + + /* 24 bits address */ + case '2': + result = sscanf (Line,"S%1x%2x%6x%s",&Type,&Nb_Bytes,&Address,Data_Str); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + Checksum = Nb_Bytes + (Address >> 16) + (Address >> 8) + (Address & 0xFF); + + /* Adjust Nb_Bytes for the number of data bytes */ + Nb_Bytes = Nb_Bytes - 4; + break; + + /* 32 bits address */ + case '3': + result = sscanf (Line,"S%1x%2x%8x%s",&Type,&Nb_Bytes,&Address,Data_Str); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + Checksum = Nb_Bytes + (Address >> 24) + (Address >> 16) + (Address >> 8) + (Address & 0xFF); + + /* Adjust Nb_Bytes for the number of data bytes */ + Nb_Bytes = Nb_Bytes - 5; + break; + + case '5': + result = sscanf (Line,"S%1x%2x%4x%2x",&Type,&Nb_Bytes,&Record_Count,&Record_Checksum); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + Checksum = Nb_Bytes + (Record_Count >> 8) + (Record_Count & 0xFF); + + /* Adjust Nb_Bytes for the number of data bytes */ + Nb_Bytes = 0; + break; + + case '7': + result = sscanf (Line,"S%1x%2x%8x%2x",&Type,&Nb_Bytes,&Exec_Address,&Record_Checksum); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + Checksum = Nb_Bytes + (Exec_Address >> 24) + (Exec_Address >> 16) + (Exec_Address >> 8) + (Exec_Address & 0xFF); + Nb_Bytes = 0; + break; + + case '8': + result = sscanf (Line,"S%1x%2x%6x%2x",&Type,&Nb_Bytes,&Exec_Address,&Record_Checksum); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + Checksum = Nb_Bytes + (Exec_Address >> 16) + (Exec_Address >> 8) + (Exec_Address & 0xFF); + Nb_Bytes = 0; + break; + case '9': + result = sscanf (Line,"S%1x%2x%4x%2x",&Type,&Nb_Bytes,&Exec_Address,&Record_Checksum); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + Checksum = Nb_Bytes + (Exec_Address >> 8) + (Exec_Address & 0xFF); + Nb_Bytes = 0; + break; + } + + p = (char *) Data_Str; + + /* If we're reading the last record, ignore it. */ + switch (Type) + { + /* Data record */ + case 1: + case 2: + case 3: + if (Nb_Bytes == 0) + { + fprintf(stderr,"0 byte length Data record ignored\n"); + break; + } + + Phys_Addr = Address; + + /* Read the Data bytes. */ + i = Nb_Bytes; + + do + { + result = sscanf (p, "%2x",&temp2); + if (result != 1) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + p += 2; + + /* Overlapping record will erase the pad bytes */ + if (Swap_Wordwise) + { + if (Memory_Block[Phys_Addr ^ 1] != Pad_Byte) fprintf(stderr,"Overlapped record detected\n"); + Memory_Block[Phys_Addr++ ^ 1] = temp2; + } + else + { + if (Memory_Block[Phys_Addr] != Pad_Byte) fprintf(stderr,"Overlapped record detected\n"); + Memory_Block[Phys_Addr++] = temp2; + } + + Checksum = (Checksum + temp2) & 0xFF; + } + while (--i != 0); + + /* Read the Checksum value. */ + result = sscanf (p, "%2x",&Record_Checksum); + if (result != 1) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + break; + + case 5: + fprintf(stderr,"Record total: %d\n",Record_Count); + break; + + case 7: + fprintf(stderr,"Execution Address (unused): %08X\n",Exec_Address); + break; + + case 8: + fprintf(stderr,"Execution Address (unused): %06X\n",Exec_Address); + break; + + case 9: + fprintf(stderr,"Execution Address (unused): %04X\n",Exec_Address); + break; + + /* Ignore all other records */ + default:; + } + + Record_Checksum &= 0xFF; + + /* Verify Checksum value. */ + if (((Record_Checksum + Checksum) != 0xFF) && Enable_Checksum_Error) + { + fprintf(stderr,"Checksum error in record %d: should be %02X\n",Record_Nb, 255-Checksum); + Status_Checksum_Error = true; + } + } + } + while (!feof (Filin)); + /*-----------------------------------------------------------------------------*/ + + fprintf(stdout,"Binary file start = %08X\n",Lowest_Address); + fprintf(stdout,"Records start = %08X\n",Records_Start); + fprintf(stdout,"Highest address = %08X\n",Highest_Address); + fprintf(stdout,"Pad Byte = %X\n", Pad_Byte); + + WriteMemory(); + +#ifdef USE_FILE_BUFFERS + free (FilinBuf); + free (FiloutBuf); +#endif + + fclose (Filin); + fclose (Filout); + + if (Status_Checksum_Error && Enable_Checksum_Error) + { + fprintf(stderr,"Checksum error detected.\n"); + return 1; + } + + if (!Fileread) + usage(); + return 0; +} diff --git a/tools/iDSK/.gitignore b/tools/iDSK/.gitignore new file mode 100644 index 0000000..4d731b8 --- /dev/null +++ b/tools/iDSK/.gitignore @@ -0,0 +1,7 @@ +CMakeFiles +CMakeCache.txt +*.cmake +iDSK.* +Makefile +*.swp +*.dsk diff --git a/tools/iDSK/AUTHORS b/tools/iDSK/AUTHORS new file mode 100644 index 0000000..0c18ff6 --- /dev/null +++ b/tools/iDSK/AUTHORS @@ -0,0 +1,3 @@ +cpcemu - Marco Vieth +manageDSK - Ludovic Deplanque +iDSK - Sid from IMPACT / PulkoMandy from the Shinra Team diff --git a/tools/iDSK/CMakeLists.txt b/tools/iDSK/CMakeLists.txt new file mode 100644 index 0000000..b15c716 --- /dev/null +++ b/tools/iDSK/CMakeLists.txt @@ -0,0 +1,14 @@ +PROJECT(iDSK) + +add_executable(iDSK + src/Basic.cpp + src/BitmapCPC.cpp + src/Dams.cpp + src/Desass.cpp + src/endianPPC.cpp + src/GestDsk.cpp + src/getopt_pp.cpp + src/Main.cpp + src/Outils.cpp + src/ViewFile.cpp +) diff --git a/tools/iDSK/COPYING b/tools/iDSK/COPYING new file mode 100644 index 0000000..b515066 --- /dev/null +++ b/tools/iDSK/COPYING @@ -0,0 +1 @@ +Well, ask Sid before doing anything... diff --git a/tools/iDSK/src/Basic.cpp b/tools/iDSK/src/Basic.cpp new file mode 100644 index 0000000..4aeb314 --- /dev/null +++ b/tools/iDSK/src/Basic.cpp @@ -0,0 +1,350 @@ +#include +using namespace std; +#include +#include +#include +#include + +#include "MyType.h" +#include "Basic.h" + + +//static char ConvCpcFr[ 128 ] = " !\"#$%&'()*+,-./0123456789:;<=>?àABCDEFGHIJKLMNOPQRSTUVWXYZ[ç]^_`abcdefghijklmnopqrstuvwxyzéùè~"; + + +// +// Tableau de décryptage d'un programme en basic protégé +// +static BYTE DproBasic[ 128 ] = + { + 0xAB, 0x2C, 0xED, 0xEA, 0x6C, 0x37, 0x3F, 0xEC, + 0x9B, 0xDF, 0x7A, 0x0C, 0x3B, 0xD4, 0x6D, 0xF5, + 0x04, 0x44, 0x03, 0x11, 0xDF, 0x59, 0x8F, 0x21, + 0x73, 0x7A, 0xCC, 0x83, 0xDD, 0x30, 0x6A, 0x30, + 0xD3, 0x8F, 0x02, 0xF0, 0x60, 0x6B, 0x94, 0xE4, + 0xB7, 0xF3, 0x03, 0xA8, 0x60, 0x88, 0xF0, 0x43, + 0xE8, 0x8E, 0x43, 0xA0, 0xCA, 0x84, 0x31, 0x53, + 0xF3, 0x1F, 0xC9, 0xE8, 0xAD, 0xC0, 0xBA, 0x6D, + 0x93, 0x08, 0xD4, 0x6A, 0x2C, 0xB2, 0x07, 0x27, + 0xC0, 0x99, 0xEE, 0x89, 0xAF, 0xC3, 0x53, 0xAB, + 0x2B, 0x34, 0x5C, 0x2F, 0x13, 0xEE, 0xAA, 0x2C, + 0xD9, 0xF4, 0xBC, 0x12, 0xB3, 0xC5, 0x1C, 0x68, + 0x01, 0x20, 0x2C, 0xFA, 0x77, 0xA6, 0xB5, 0xA4, + 0xFC, 0x9B, 0xF1, 0x32, 0x5B, 0xC3, 0x70, 0x77, + 0x85, 0x36, 0xBE, 0x5B, 0x8C, 0xC8, 0xB5, 0xC2, + 0xF0, 0x0B, 0x98, 0x0F, 0x36, 0x9D, 0xD8, 0x96 + }; + + +BYTE GetByte( BYTE * BufFile, int Pos, int Deprotect ) +{ + //BYTE b = ( BYTE )( BufFile[ Pos ] ^ ( DproBasic[ Pos & 0x7F ] * Deprotect ) ); + //cout << "GetByte:"<", "=", ">=", "<", "<>", + "<=", "+", "-", "*", "/", "^", "\\ ", "AND", "MOD", "OR", "XOR", "NOT", + "#FF" + }; + + static const char * Fcts[ 0x80 ] = + { + "ABS", "ASC", "ATN", "CHR$", "CINT", "COS", "CREAL", "EXP", "FIX", + "FRE", "INKEY", "INP", "INT", "JOY", "LEN", "LOG", "LOG10", "LOWER$", + "PEEK", "REMAIN", "SGN", "SIN", "SPACE$", "SQ", "SQR", "STR$", "TAN", + "UNT", "UPPER$", "VAL", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "EOF", "ERR", "HIMEM", "INKEY$", "PI", "RND", + "TIME", "XPOS", "YPOS", "DERR", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "BIN$", "DEC$", "HEX$", + "INSTR", "LEFT$", "MAX", "MIN", "POS", "RIGHT$", "ROUND", "STRING$", + "TEST", "TESTR", "COPYCHR$", "VPOS" + }; + + + * Listing = 0; + Token = GetByte( BufFile, 0, Deprotect ); + for ( ;; ) + { + //cout << "Listing : " < 0x7F && Token < 0xFF ) + { + // #### Traitement particulier du ':' avant le ELSE + if ( Listing[ strlen( Listing ) - 1 ] == ':' + && Token == 0x97 + ) + Listing[ strlen( Listing ) - 1 ] = 0; + + strcat( Listing + , MotsClefs[ Token & 0x7F ] + ); + } + else + if ( Token >= 0x0E && Token <= 0x18 ) + strcat( Listing + , Nbre[ Token - 0x0E ] + ); + else + if ( Token >= 0x20 && Token < 0x7C ) + { + Tmp[ 0 ] = ( char )Token; + Tmp[ 1 ] = 0; + strcat( Listing, Tmp ); + if ( Token == '"' ) + DansChaine ^= 1; + } + else + { + //cout << "Token:" << Token < 80 caractères + // + EndLigne = strlen( &Listing[ StartLigne ] ); + while( EndLigne > 80 ) + { + memmove( &Listing[ StartLigne + 82 ] + , &Listing[ StartLigne + 80 ] + , EndLigne + ); + memcpy( &Listing[ StartLigne + 80 ], "\r\n", 2 ); + StartLigne += 82; + EndLigne -= 80; + } + } + strcat( Listing, "\r\n" ); + StartLigne = strlen( Listing ); + } + // Conversion des caractères accentués si nécessaire + + for ( int i = strlen( Listing); i--; ) + { + //cout << i << " "; + + if ( ! isprint(Listing[ i ]) && Listing[ i ] != '\n' && Listing[ i ] != '\r' ) Listing[ i ] = '?'; + } +} diff --git a/tools/iDSK/src/Basic.h b/tools/iDSK/src/Basic.h new file mode 100644 index 0000000..bb99181 --- /dev/null +++ b/tools/iDSK/src/Basic.h @@ -0,0 +1,8 @@ +#ifndef BASIC_H +#define BASIC_H + + +void Basic( unsigned char * BufFile, char * Listing, bool IsBasic, bool CrLf ); + + +#endif diff --git a/tools/iDSK/src/BitmapCPC.cpp b/tools/iDSK/src/BitmapCPC.cpp new file mode 100644 index 0000000..19b39a6 --- /dev/null +++ b/tools/iDSK/src/BitmapCPC.cpp @@ -0,0 +1,264 @@ +#include +#include +#include "MyType.h" +#include "BitmapCPC.h" +#include "GestDsk.h" +#include +#include +using namespace std; + + +// +// Couleurs du CPC converties en composantes r, v, b +// +static StRVB RgbCPC[ 27 ] = + { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x7F, 0x00, 0x00, 0x00 }, + { 0xFF, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x7F, 0x00 }, + { 0x7F, 0x00, 0x7F, 0x00 }, + { 0xFF, 0x00, 0x7F, 0x00 }, + { 0x00, 0x00, 0xFF, 0x00 }, + { 0x7F, 0x00, 0xFF, 0x00 }, + { 0xFF, 0x00, 0xFF, 0x00 }, + { 0x00, 0x7F, 0x00, 0x00 }, + { 0x7F, 0x7F, 0x00, 0x00 }, + { 0xFF, 0x7F, 0x00, 0x00 }, + { 0x00, 0x7F, 0x7F, 0x00 }, + { 0x7F, 0x7F, 0x7F, 0x00 }, + { 0xFF, 0x7F, 0x7F, 0x00 }, + { 0x00, 0x7F, 0xFF, 0x00 }, + { 0x7F, 0x7F, 0xFF, 0x00 }, + { 0xFF, 0x7F, 0xFF, 0x00 }, + { 0x00, 0xFF, 0x00, 0x00 }, + { 0x7F, 0xFF, 0x00, 0x00 }, + { 0xFF, 0xFF, 0x00, 0x00 }, + { 0x00, 0xFF, 0x7F, 0x00 }, + { 0x7F, 0xFF, 0x7F, 0x00 }, + { 0xFF, 0xFF, 0x7F, 0x00 }, + { 0x00, 0xFF, 0xFF, 0x00 }, + { 0x7F, 0xFF, 0xFF, 0x00 }, + { 0xFF, 0xFF, 0xFF, 0x00 } + }; + + +int GetRgbCPC( int Coul ) +{ + if ( Coul >= 0 && Coul < 27 ) + { + StRVB i = RgbCPC[ Coul ]; + return( ( i.b << 16 ) + ( i.v << 8 ) + i.r ); + } + return( -1 ); +} + + +StRVB GetPalCPC( int Coul ) +{ + if ( Coul >= 0 && Coul < 27 ) + return( RgbCPC[ Coul ] ); + + return( RgbCPC[ 0 ] ); +} + + +void InitPalette( unsigned char NewPal[ 16 ], bool SetNewPal ) +{ + /* + Si sauvegard� avec ConvImgCpc, alors la palette se trouve + dans l'image... + */ + int i; + if ( BitmapCPC[ 0x7D0 ] == 0x3A + && BitmapCPC[ 0x7D1 ] == 0xD0 + && BitmapCPC[ 0x7D2 ] == 0xD7 + && BitmapCPC[ 0x7D3 ] == 0xCD + ) + { + Mode = BitmapCPC[ 0x17D0 ]; + for ( i = 0; i < 16; i++ ) + Palette[ i ] = BitmapCPC[ 0x17D1 + i ]; + } + if ( SetNewPal ) + for ( i = 0; i < 16; i++ ) + Palette[ i ] = NewPal[ i ]; +} + + +// +// D�compacter une image au format OCP +// +void DepactOCP( void ) +{ + static unsigned char BufTmp[ 0x4000 ]; + int PosIn = 0, PosOut = 0; + int LgOut, CntBlock = 0; + int c,i; + unsigned char a; + memcpy( BufTmp, BitmapCPC, sizeof( BufTmp ) ); + memset( BitmapCPC, 0, 0x4000 ); + while( PosOut < 0x4000 ) + { + if ( ! strncmp( ( char * )&BufTmp[ PosIn ], "MJH", 3 ) ) + { + PosIn += 3; + LgOut = BufTmp[ PosIn++ ]; + LgOut += ( BufTmp[ PosIn++ ] << 8 ); + CntBlock = 0; + while( CntBlock < LgOut ) + { + if ( ! strncmp( ( char * )&BufTmp[ PosIn ], "MJH", 3 ) ) + break; + + a = BufTmp[ PosIn++ ]; + if ( a == MARKER_OCP ) + { + c = BufTmp[ PosIn++ ]; + a = BufTmp[ PosIn++ ]; + if ( ! c ) + c = 0x100; + + for ( i = 0; i < c && CntBlock < LgOut; i++ ) + { + BitmapCPC[ PosOut++ ] = a; + CntBlock++; + } + } + else + { + BitmapCPC[ PosOut++ ] = a; + CntBlock++; + } + } + } + else + PosOut = 0x4000; + } +} + + +bool LireImage( char * Nom, StRVB * Bitmap ) +{ + static unsigned char Entete[ 0x80 ]; + bool Ret = FALSE; + //DWORD Nb; + FILE* hFile; + + + if ( (hFile=fopen(Nom,"rb"))!=NULL ) + { + fread(Entete,sizeof(Entete),1,hFile); + // ReadFile( hFile, Entete, sizeof( Entete ), &Nb, NULL ); + if ( CheckAmsdos( Entete ) ) + { + fread(BitmapCPC,sizeof( BitmapCPC ),1,hFile); + // ReadFile( hFile, BitmapCPC, sizeof( BitmapCPC ), &Nb, NULL ); + if ( ! strncmp( ( char * )BitmapCPC, "MJH", 3 ) ) + DepactOCP(); + + InitPalette( NULL, FALSE ); + Ret = TRUE; + } + // CloseHandle( hFile ); + fclose(hFile); + if ( Ret ) + Render( Bitmap, 1 ); + } + return( Ret ); + +} + + +// +// Affiche l'image � l'�cran +// +void Render( StRVB * Bitmap, bool Flat ) +{ + int AdrCPC = 0, i, p0, p1, p2, p3; + int y,x,AdrBitmap; + unsigned char Octet; + for ( y = 0; y < NbLignes; y++ ) + { + AdrBitmap = TAILLE_CPC_X * ( y + ( ( 200 - NbLignes ) >> 1 ) ) + + ( ( ( 80 - NbCol ) >> 1 ) << 3 ); + for ( x = 0; x < NbCol; x++ ) + { + Octet = BitmapCPC[ AdrCPC + x ]; + switch( Mode ) + { + case 0 : + case 3 : // Mode 3 = Mode 0 + p0 = ( Octet >> 7 ) + + ( ( Octet & 0x20 ) >> 3 ) + + ( ( Octet & 0x08 ) >> 2 ) + + ( ( Octet & 0x02 ) << 2 ); + p1 = ( ( Octet & 0x40 ) >> 6 ) + + ( ( Octet & 0x10 ) >> 2 ) + + ( ( Octet & 0x04 ) >> 1 ) + + ( ( Octet & 0x01 ) << 3 ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p0 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p0 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p0 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p0 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p1 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p1 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p1 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p1 ] ); + break; + + case 1 : + p0 = ( ( Octet >> 7 ) & 1 ) + ( ( Octet >> 2 ) & 2 ); + p1 = ( ( Octet >> 6 ) & 1 ) + ( ( Octet >> 1 ) & 2 ); + p2 = ( ( Octet >> 5 ) & 1 ) + ( ( Octet >> 0 ) & 2 ); + p3 = ( ( Octet >> 4 ) & 1 ) + ( ( Octet << 1 ) & 2 ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p0 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p0 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p1 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p1 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p2 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p2 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p3 ] ); + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p3 ] ); + break; + + case 2 : + for ( i = 8; i--; ) + Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ ( Octet >> i ) & 1 ] ); + break; + } + } + if ( Flat ) + AdrCPC += NbCol; + else + { + AdrCPC += 0x800; + if ( AdrCPC > 0x3FFF ) + AdrCPC -= 0x3FB0; + } + } +} + + +void SetBitmapCPC( unsigned char * BitmapSource ) +{ + memcpy( BitmapCPC, BitmapSource, 0x4000 ); + if ( ! strncmp( ( char * )BitmapCPC, "MJH", 3 ) ) + DepactOCP(); + + InitPalette( NULL, FALSE ); +} + + +void SetNbCol( int n ) +{ + if ( n > 0 && n <= 80 ) + NbCol = n; +} + + +void SetNbLignes( int n ) +{ + if ( n > 0 && n <= 200 ) + NbLignes = n; +} diff --git a/tools/iDSK/src/BitmapCPC.h b/tools/iDSK/src/BitmapCPC.h new file mode 100644 index 0000000..2af2bab --- /dev/null +++ b/tools/iDSK/src/BitmapCPC.h @@ -0,0 +1,46 @@ +#ifndef BITMAPCPC_H +#define BITMAPCPC_H + + +#define TAILLE_CPC_X 640 + +#define TAILLE_CPC_Y 200 + +#define MARKER_OCP 1 // Marker pour compression RLE +int Mode, NbCol, NbLignes; +unsigned char BitmapCPC[ 0x4000 ]; +unsigned char Palette[ 16 ]; +typedef struct + { + unsigned char b, v, r, a; + } StRVB; + + + +void CBitmapCPC( void ) { NbCol = 80; NbLignes = 200; } +bool LireImage( char * Nom, StRVB * Bitmap ); +void Render( StRVB * Bitmap, bool Flat ); +void SetBitmapCPC( unsigned char * BitmapSource ); +unsigned char * GetBitmapCPC( void ) { return( BitmapCPC ); } +void SetMode( int m ) { Mode = m; } +void InitPalette( unsigned char Pal[ 16 ], bool SetPal ); +unsigned char * GetPalette( void ) { return( Palette ); } +int GetMode( void ) { return( Mode ); } +void SetNbCol( int n ); +void SetNbLignes( int n ); + + +void DepactOCP( void ); +void LisseBitmap( StRVB * Bitmap ); + + + + + + +StRVB GetPalCPC( int Coul ); + +int GetRgbCPC( int Coul ); + + +#endif diff --git a/tools/iDSK/src/Dams.cpp b/tools/iDSK/src/Dams.cpp new file mode 100644 index 0000000..9b24813 --- /dev/null +++ b/tools/iDSK/src/Dams.cpp @@ -0,0 +1,184 @@ +#include +#include +#include +using namespace std; + + +// +// Convertir le buffer en listing au format Dams +// Adaptation des sources de Thierry JOUIN ( Ramlaid ) +// +void Dams( unsigned char * BufFile, int TailleFic, char * Listing ) +{ + const char * MotCleDams[ 0x80 ] = + { + "LD","INC","DEC","ADD","ADC","SUB","SBC","AND","XOR","OR","CP", + "PUSH","POP","BIT","RES","SET","RLC","RRC","RL","RR","SLA","SRA", + "SRL","IN","OUT","RST","DJNZ","EX","IM","JR","CALL","RET","JP", + "NOP","RLCA","RRCA","RLA","RRA","DAA","CPL","SCF","CCF","HALT", + "EXX","DI","EI","NEG","RETN","RETI","RRD","RLD","LDI","CPI","INI", + "OUTI","LDD","CPD","IND","OUTD","LDIR","CPIR","INIR","OTIR","LDDR", + "CPDR","INDR","OTDR","DB","DW","DM","DS","EQU","ORG","ENT", + "IF","ELSE","END" + }; + char Tmp[ 32 ]; + int PosFile = 0; + int PosDest = 0; + unsigned char c; + + * Listing = 0; + c = BufFile[ PosFile++ ]; + while( c ) + { + if ( c == 0xFF ) + { + // Commentaire ligne + Listing[ PosDest++ ] = ';'; + c = BufFile[ PosFile++ ]; + while( c != 0x0D && PosFile < TailleFic ) + { + Listing[ PosDest++ ] = c; + c = BufFile[ PosFile++ ]; + } + Listing[ PosDest++ ] = '\r'; + Listing[ PosDest++ ] = '\n'; + } + else + { + if ( c >= 0x80 && c != 0x0D ) + { + // Mnemonique sans label + // ENT + if ( c == 0xC9 ) + Listing[ PosDest++ ] = ';'; + + sprintf( Tmp, "\t%s\t", MotCleDams[ c & 0x7F ] ); + int l = strlen( Tmp ); + memcpy( &Listing[ PosDest ], Tmp, l ); + PosDest += l; + // DS ?,? + if ( c == 0xC6 ) + { + c = BufFile[ PosFile++ ]; + // Fin de ligne + while( c != 0x0D && PosFile < TailleFic ) + { + if ( c == ',' ) + { + while( c != 0x0D && c != 0xFF && PosFile < TailleFic ) + c = BufFile[ PosFile++ ]; + } + if ( c != 0x0D ) + { + if ( c == 0xFF ) + Listing[ PosDest++ ] = '\t'; + else + Listing[ PosDest++ ] = c; + + c = BufFile[ PosFile++ ]; + } + } + } + else + { + c = BufFile[ PosFile++ ]; + // Fin de ligne + while( c != 0x0D && PosFile < TailleFic ) + { + if ( c == 0xFF ) + Listing[ PosDest++ ] = '\t'; + else + Listing[ PosDest++ ] = c; + + c = BufFile[ PosFile++ ]; + } + } + Listing[ PosDest++ ] = '\r'; + Listing[ PosDest++ ] = '\n'; + } + else + { + // Label + while( c < 0x80 && c != 0x0D && PosFile < TailleFic ) + { + Listing[ PosDest++ ] = c; + c = BufFile[ PosFile++ ]; + } + if ( c != 0x0D ) + { + // Mnemonique apres label + // ENT + if ( c == 0xC9 ) + Listing[ PosDest++ ] = ';'; + + if ( c != 0xFF ) + { + sprintf( Tmp, "\t%s\t", MotCleDams[ c & 0x7F ] ); + int l = strlen( Tmp ); + memcpy( &Listing[ PosDest ], Tmp, l ); + PosDest += l; + } + else + { + Listing[ PosDest++ ] = '\t'; + Listing[ PosDest++ ] = '\t'; + Listing[ PosDest++ ] = '\t'; + } + // DS ?,? + if ( c == 0xC6 ) + { + c = BufFile[ PosFile++ ]; + // Fin de ligne + while( c != 0x0D && PosFile < TailleFic ) + { + if ( c == ',' ) + { + while( c != 0x0D && c != 0xFF && PosFile < TailleFic ) + c = BufFile[ PosFile++ ]; + } + if ( c != 0x0D ) + { + if ( c == 0xFF ) + { + Listing[ PosDest++ ] = '\t'; + Listing[ PosDest++ ] = ';'; + } + else + Listing[ PosDest++ ] = c; + + c = BufFile[ PosFile++ ]; + } + } + } + else + { + c = BufFile[ PosFile++ ]; + // Fin de ligne + while( c != 0x0D && PosFile < TailleFic ) + { + if ( c == 0xFF ) + { + Listing[ PosDest++ ] = '\t'; + Listing[ PosDest++ ] = ';'; + } + else + Listing[ PosDest++ ] = c; + + c = BufFile[ PosFile++ ]; + } + } + Listing[ PosDest++ ] = '\r'; + Listing[ PosDest++ ] = '\n'; + } + else + { + Listing[ PosDest++ ] = '\r'; + Listing[ PosDest++ ] = '\n'; + } + } + } + c = BufFile[ PosFile++ ]; + if ( PosFile > TailleFic ) + break; + } +} diff --git a/tools/iDSK/src/Dams.h b/tools/iDSK/src/Dams.h new file mode 100644 index 0000000..6610ef7 --- /dev/null +++ b/tools/iDSK/src/Dams.h @@ -0,0 +1,8 @@ +#ifndef DAMS_H +#define DAMS_H + + +void Dams( unsigned char * BufFile, int TailleFic, char * Listing ); + + +#endif diff --git a/tools/iDSK/src/Desass.cpp b/tools/iDSK/src/Desass.cpp new file mode 100644 index 0000000..a2030a0 --- /dev/null +++ b/tools/iDSK/src/Desass.cpp @@ -0,0 +1,532 @@ +#include +#include +#include + +#include "Outils.h" +using namespace std; + + +// +// Tableau des OP-Codes Z80... +// +const char * TabInstrCB[ 256 ] = + { + "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" + }; + + +const char * TabInstrED[ 256 ] = + { + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + "IN B,(C)","OUT (C),B","SBC HL,BC","LD (nnnn),BC", + "NEG","RETN","IM 0","LD I,A", + "IN C,(C)","OUT (C),C","ADC HL,BC","LD BC,(nnnn)", + 0,"RETI",0,"LD R,A", + "IN D,(C)","OUT (C),D","SBC HL,DE","LD (nnnn),DE", + 0,0,"IM 1","LD A,I", + "IN E,(C)","OUT (C),E","ADC HL,DE","LD DE,(nnnn)", + 0,0,"IM 2","LD A,R", + "IN H,(C)","OUT (C),H","SBC HL,HL",0, + 0,0,0,"RRD", + "IN L,(C)","OUT (C),L","ADC HL,HL",0, + 0,0,0,"RLD", + 0,"OUT (C),0","SBC HL,SP","LD (nnnn),SP", + 0,0,0,0, + "IN A,(C)","OUT (C),A","ADC HL,SP","LD SP,(nnnn)", + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + "LDI","CPI","INI","OUTI", + 0,0,0,0, + "LDD","CPD","IND","OUTD", + 0,0,0,0, + "LDIR","CPIR","INIR","OTIR", + 0,0,0,0, + "LDDR","CPDR","INDR","OTDR", + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0 + }; + + +const char * TabInstrDD[ 256 ] = + { + 0,0,0,0, + 0,0,0,0, + 0,"ADD IX,BC",0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,"ADD IX,DE",0,0, + 0,0,0,0, + 0,"LD IX,nnnn","LD (nnnn),IX","INC IX", + "INC IXh","DEC IXh","LD IXh,nn",0, + 0,"ADD IX,HL","LD IX,(nnnn)","DEC IX", + "INC IXl","DEC IXl","LD IXl,nn",0, + 0,0,0,0, + "INC (IX+nn)","DEC (IX+nn)","LD (IX+nn),nn",0, + 0,"ADD IX,SP",0,0, + 0,0,0,0, + 0,0,0,0, + "LD B,IXh","LD B,IXl","LD B,(IX+nn)",0, + 0,0,0,0, + "LD C,IXh","LD C,IXl","LD C,(IX+nn)",0, + 0,0,0,0, + "LD D,IXh","LD D,IXl","LD D,(IX+nn)",0, + 0,0,0,0, + "LD E,IXh","LD E,IXl","LD E,(IX+nn)",0, + "LD IXh,B","LD IXh,C","LD IXh,D","LD IXh,E", + "LD IXh,IXh","LD IXh,IXl","LD H,(IX+nn)","LD IXh,A", + "LD IXl,B","LD IXl,C","LD IXl,D","LD IXl,E", + "LD IXl,IXh","LD IXl,IXl","LD L,(IX+nn)","LD IXl,A", + "LD (IX+nn),B","LD (IX+nn),C","LD (IX+nn),D","LD (IX+nn),E", + "LD (IX+nn),H","LD (IX+nn),L",0,"LD (IX+nn),A", + 0,0,0,0, + "LD A,IXh","LD A,IXl","LD A,(IX+nn)",0, + 0,0,0,0, + "ADD A,IXh","ADD A,IXl","ADD A,(IX+nn)",0, + 0,0,0,0, + "ADC A,IXh","ADC A,IXl","ADC A,(IX+nn)",0, + 0,0,0,0, + "SUB IXh","SUB IXl","SUB (IX+nn)",0, + 0,0,0,0, + "SBC A,IXh","SBC A,IXl","SBC A,(IX+nn)",0, + 0,0,0,0, + "AND IXh","AND IXl","AND (IX+nn)",0, + 0,0,0,0, + "XOR IXh","XOR IXl","XOR (IX+nn)",0, + 0,0,0,0, + "OR IXh","OR IXl","OR (IX+nn)",0, + 0,0,0,0, + "CP IXh","CP IXl","CP (IX+nn)",0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,"POP IX",0,"EX (SP),IX", + 0,"PUSH IX",0,0, + 0,"JP (IX)",0,0, + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 0,"LD SP,IX",0,0, + 0,0,0,0 + }; + + +const char * TabInstrDDCB[ 256 ] = + { + 0,0,0,0,0,0,"RLC (IX+nn)",0, + 0,0,0,0,0,0,"RRC (IX+nn)",0, + 0,0,0,0,0,0,"RL (IX+nn)",0, + 0,0,0,0,0,0,"RR (IX+nn)",0, + 0,0,0,0,0,0,"SLA (IX+nn)",0, + 0,0,0,0,0,0,"SRA (IX+nn)",0, + 0,0,0,0,0,0,"SLL (IX+nn)",0, + 0,0,0,0,0,0,"SRL (IX+nn)",0, + 0,0,0,0,0,0,"BIT 0,(IX+nn)",0, + 0,0,0,0,0,0,"BIT 1,(IX+nn)",0, + 0,0,0,0,0,0,"BIT 2,(IX+nn)",0, + 0,0,0,0,0,0,"BIT 3,(IX+nn)",0, + 0,0,0,0,0,0,"BIT 4,(IX+nn)",0, + 0,0,0,0,0,0,"BIT 5,(IX+nn)",0, + 0,0,0,0,0,0,"BIT 6,(IX+nn)",0, + 0,0,0,0,0,0,"BIT 7,(IX+nn)",0, + 0,0,0,0,0,0,"RES 0,(IX+nn)",0, + 0,0,0,0,0,0,"RES 1,(IX+nn)",0, + 0,0,0,0,0,0,"RES 2,(IX+nn)",0, + 0,0,0,0,0,0,"RES 3,(IX+nn)",0, + 0,0,0,0,0,0,"RES 4,(IX+nn)",0, + 0,0,0,0,0,0,"RES 5,(IX+nn)",0, + 0,0,0,0,0,0,"RES 6,(IX+nn)",0, + 0,0,0,0,0,0,"RES 7,(IX+nn)",0, + 0,0,0,0,0,0,"SET 0,(IX+nn)",0, + 0,0,0,0,0,0,"SET 1,(IX+nn)",0, + 0,0,0,0,0,0,"SET 2,(IX+nn)",0, + 0,0,0,0,0,0,"SET 3,(IX+nn)",0, + 0,0,0,0,0,0,"SET 4,(IX+nn)",0, + 0,0,0,0,0,0,"SET 5,(IX+nn)",0, + 0,0,0,0,0,0,"SET 6,(IX+nn)",0, + 0,0,0,0,0,0,"SET 7,(IX+nn)",0 + }; + + +const char * TabInstrFD[ 256 ] = + { + 0,0,0,0,0,0,0,0, + 0,"ADD IY,BC",0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,"ADD IY,DE",0,0,0,0,0,0, + 0,"LD IY,nnnn","LD (nnnn),IY","INC IY","INC IYh","DEC IYh","LD IYh,nn",0, + 0,"ADD IY,HL","LD IY,(nnnn)","DEC IY","INC IYl","DEC IYl","LD IYl,nn",0, + 0,0,0,0,"INC (IY+nn)","DEC (IY+nn)","LD (IY+nn),nn",0, + 0,"ADD IY,SP",0,0,0,0,0,0, + 0,0,0,0,"LD B,IYh","LD B,IYl","LD B,(IY+nn)",0, + 0,0,0,0,"LD C,IYh","LD C,IYl","LD C,(IY+nn)",0, + 0,0,0,0,"LD D,IYh","LD D,IYl","LD D,(IY+nn)",0, + 0,0,0,0,"LD E,IYh","LD E,IYl","LD E,(IY+nn)",0, + "LD IYh,B","LD IYh,C","LD IYh,D","LD IYh,E","LD IYh,IYh","LD IYh,IYl","LD H,(IY+nn)","LD IYh,A", + "LD IYl,B","LD IYl,C","LD IYl,D","LD IYl,E","LD IYl,IYh","LD IYl,IYl","LD L,(IY+nn)","LD IYl,A", + "LD (IY+nn),B","LD (IY+nn),C","LD (IY+nn),D","LD (IY+nn),E","LD (IY+nn),H","LD (IY+nn),L",0,"LD (IY+nn),A", + 0,0,0,0,"LD A,IYh","LD A,IYl","LD A,(IY+nn)",0, + 0,0,0,0,"ADD A,IYh","ADD A,IYl","ADD A,(IY+nn)",0, + 0,0,0,0,"ADC A,IYh","ADC A,IYl","ADC A,(IY+nn)",0, + 0,0,0,0,"SUB IYh","SUB IYl","SUB (IY+nn)",0, + 0,0,0,0,"SBC A,IYh","SBC A,IYl","SBC A,(IY+nn)",0, + 0,0,0,0,"AND IYh","AND IYl","AND (IY+nn)",0, + 0,0,0,0,"XOR IYh","XOR IYl","XOR (IY+nn)",0, + 0,0,0,0,"OR IYh","OR IYl","OR (IY+nn)",0, + 0,0,0,0,"CP IYh","CP IYl","CP (IY+nn)",0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,"POP IY",0,"EX (SP),IY",0,"PUSH IY",0,0, + 0,"JP (IY)",0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,"LD SP,IY",0,0,0,0,0,0 + }; + + +const char * TabInstrFDCB[ 256 ] = + { + 0,0,0,0,0,0,"RLC (IY+nn)",0, + 0,0,0,0,0,0,"RRC (IY+nn)",0, + 0,0,0,0,0,0,"RL (IY+nn)",0, + 0,0,0,0,0,0,"RR (IY+nn)",0, + 0,0,0,0,0,0,"SLA (IY+nn)",0, + 0,0,0,0,0,0,"SRA (IY+nn)",0, + 0,0,0,0,0,0,"SLL (IY+nn)",0, + 0,0,0,0,0,0,"SRL (IY+nn)",0, + 0,0,0,0,0,0,"BIT 0,(IY+nn)",0, + 0,0,0,0,0,0,"BIT 1,(IY+nn)",0, + 0,0,0,0,0,0,"BIT 2,(IY+nn)",0, + 0,0,0,0,0,0,"BIT 3,(IY+nn)",0, + 0,0,0,0,0,0,"BIT 4,(IY+nn)",0, + 0,0,0,0,0,0,"BIT 5,(IY+nn)",0, + 0,0,0,0,0,0,"BIT 6,(IY+nn)",0, + 0,0,0,0,0,0,"BIT 7,(IY+nn)",0, + 0,0,0,0,0,0,"RES 0,(IY+nn)",0, + 0,0,0,0,0,0,"RES 1,(IY+nn)",0, + 0,0,0,0,0,0,"RES 2,(IY+nn)",0, + 0,0,0,0,0,0,"RES 3,(IY+nn)",0, + 0,0,0,0,0,0,"RES 4,(IY+nn)",0, + 0,0,0,0,0,0,"RES 5,(IY+nn)",0, + 0,0,0,0,0,0,"RES 6,(IY+nn)",0, + 0,0,0,0,0,0,"RES 7,(IY+nn)",0, + 0,0,0,0,0,0,"SET 0,(IY+nn)",0, + 0,0,0,0,0,0,"SET 1,(IY+nn)",0, + 0,0,0,0,0,0,"SET 2,(IY+nn)",0, + 0,0,0,0,0,0,"SET 3,(IY+nn)",0, + 0,0,0,0,0,0,"SET 4,(IY+nn)",0, + 0,0,0,0,0,0,"SET 5,(IY+nn)",0, + 0,0,0,0,0,0,"SET 6,(IY+nn)",0, + 0,0,0,0,0,0,"SET 7,(IY+nn)",0 + }; + + +const char * TabInstr[ 256 ] = + { + "NOP","LD BC,nnnn","LD (BC),A","INC BC", + "INC B","DEC B","LD B,nn","RLCA", + "EX AF,AF","ADD HL,BC","LD A,(BC)","DEC BC", + "INC C","DEC C","LD C,nn","RRCA", + "DJNZ eeee","LD DE,nnnn","LD (DE),A","INC DE", + "INC D","DEC D","LD D,nn","RLA", + "JR eeee","ADD HL,DE","LD A,(DE)","DEC DE", + "INC E","DEC E","LD E,nn","RRA", + "JR NZ,eeee","LD HL,nnnn","LD (nnnn),HL","INC HL", + "INC H","DEC H","LD H,nn","DAA", + "JR Z,eeee","ADD HL,HL","LD HL,(nnnn)","DEC HL", + "INC L","DEC L","LD L,nn","CPL", + "JR NC,eeee","LD SP,nnnn","LD (nnnn),A","INC SP", + "INC (HL)","DEC (HL)","LD (HL),nn","SCF", + "JR C,eeee","ADD HL,SP","LD A,(nnnn)","DEC SP", + "INC A","DEC A","LD A,nn","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 A,B","ADD A,C","ADD A,D","ADD A,E", + "ADD A,H","ADD A,L","ADD A,(HL)","ADD A,A", + "ADC A,B","ADC A,C","ADC A,D","ADC A,E", + "ADC A,H","ADC A,L","ADC A,(HL)","ADC A,A", + "SUB B","SUB C","SUB D","SUB E", + "SUB H","SUB L","SUB (HL)","SUB A", + "SBC A,B","SBC A,C","SBC A,D","SBC A,E", + "SBC A,H","SBC A,L","SBC A,(HL)","SBC A,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,nnnn","JP nnnn", + "CALL NZ,nnnn","PUSH BC","ADD A,nn","RST 00", + "RET Z","RET","JP Z,nnnn",0, + "CALL Z,nnnn","CALL nnnn","ADC A,nn","RST 08", + "RET NC","POP DE","JP NC,nnnn","OUT (nn),A", + "CALL NC,nnnn","PUSH DE","SUB nn","RST 10", + "RET C","EXX","JP C,nnnn","IN A,(nn)", + "CALL C,nnnn",0,"SBC A,nn","RST 18", + "RET PE","POP HL","JP PE,nnnn","EX (SP),HL", + "CALL PE,nnnn","PUSH HL","AND nn","RST 20", + "RET PO","JP (HL)","JP PO,nnnn","EX DE,HL", + "CALL PO,nnnn",0,"XOR nn","RST 28", + "RET P","POP AF","JP P,nnnn","DI", + "CALL P,nnnn","PUSH AF","OR nn","RST 30", + "RET M","LD SP,HL","JP M,nnnn","EI", + "CALL M,nnnn",0,"CP nn","RST 38" + }; + + +// +// Convertir le buffer en listing d�sassembl� +// +void Desass( unsigned char * Prg, char * Listing, int Longueur ) +{ + int i, Instr, Inst2 = 0, Inst3 = 0, Inst4 = 0, Ad16; + const char * Chaine; + char *p; + char Inst[ 1024 ]; + + int Adr, OldAdr, PosD = 0; + char Ad8; + + * Listing = 0; + for ( Adr = 0; Adr < Longueur; ) + { + OldAdr = Adr; + Instr = Prg[ Adr++ ]; + Chaine = TabInstr[ Instr ]; + if ( Instr == 0xCB ) + { + Inst2 = Prg[ Adr++ ]; + Chaine = TabInstrCB[ Inst2 ]; + } + else + if ( Instr == 0xDD ) + { + Inst2 = Prg[ Adr++ ]; + if ( Inst2 == 0xCB ) + { + Inst3 = Prg[ Adr++ ]; + Inst4 = Prg[ Adr++ ]; + Chaine = TabInstrDDCB[ Inst4 ]; + strcpy( Inst, Chaine ); + p = strstr( Inst, "nn" ); + if ( p ) + { + if ( Inst3 < 0x80 ) + Hex( p, Inst3, 2 ); + else + { + Hex( p, -Inst3, 2 ); + p[ -1 ] = '-'; + } + } + Chaine = Inst; + } + else + Chaine = TabInstrDD[ Inst2 ]; + } + else + if ( Instr == 0xED ) + { + Inst2 = Prg[ Adr++ ]; + Chaine = TabInstrED[ Inst2 ]; + } + else + if ( Instr == 0xFD ) + { + Inst2 = Prg[ Adr++ ]; + if ( Inst2 == 0xCB ) + { + Ad8 = Prg[ Adr++ ]; + Inst3 = Prg[ Adr++ ]; + Chaine = TabInstrFDCB[ Inst3 ]; + if ( Chaine ) + { + strcpy( Inst, Chaine ); + Chaine = Inst; + p = strstr( Inst, "nn" ); + if ( p ) + Hex( p, Ad8, 2 ); + } + } + else + Chaine = TabInstrFD[ Inst2 ]; + } + if ( Chaine ) + { + strcpy( Inst, Chaine ); + p = strstr( Inst, "nnnn" ); + Ad16 = Prg[ Adr++ ]; + Ad16 += Prg[ Adr ] << 8; + Ad8 = ( char ) Ad16; + if ( p ) + { + Hex( p, Ad16, 4 ); + Adr++; + } + else + { + p = strstr( Inst, "nn" ); + if ( p ) + { + Hex( p, Ad16, 2 ); + p = strstr( Inst, "nn" ); + if ( p ) + Hex( p, Ad16 >> 8, 2 ); + } + else + { + p = strstr( Inst, "eeee" ); + if ( p ) + Hex( p, Adr + Ad8, 4 ); + else + Adr--; + } + } + } + else + sprintf( Inst, "%02X %02X %02X ????", Instr, Inst2, Inst3 ); + + Hex( &Listing[ PosD ], OldAdr, 4 ); + Listing[ PosD + 4 ] = ' '; + PosD += 5; + for ( i = OldAdr; i < Adr; i++ ) + { + Hex( &Listing[ PosD ], Prg[ i ], 2 ); + Listing[ PosD + 2 ] = ' '; + PosD += 3; + } + for ( i = 0; i < 5 - Adr + OldAdr; i++ ) + { + Listing[ PosD ] = Listing[ PosD + 1 ] = Listing[ PosD + 2 ] = ' '; + PosD += 3; + } + char * p = Inst; + while( * p ) + Listing[ PosD++ ] = * p++; + + Listing[ PosD++ ] = '\r'; + Listing[ PosD++ ] = '\n'; + } +} diff --git a/tools/iDSK/src/Desass.h b/tools/iDSK/src/Desass.h new file mode 100644 index 0000000..647f535 --- /dev/null +++ b/tools/iDSK/src/Desass.h @@ -0,0 +1,8 @@ +#ifndef DESASS_H +#define DESASS_H + + +void Desass( unsigned char * Prg, char * Desass, int Longueur ); + + +#endif diff --git a/tools/iDSK/src/GestDsk.cpp b/tools/iDSK/src/GestDsk.cpp new file mode 100644 index 0000000..f1063cd --- /dev/null +++ b/tools/iDSK/src/GestDsk.cpp @@ -0,0 +1,1183 @@ +#include +#include +#include +#include +#include +#include + +#include "MyType.h" +#include "GestDsk.h" +#include "endianPPC.h" +#include "Outils.h" +#include + +#ifdef _MSC_VER +#define snprintf _snprintf +#endif + +using namespace std; + +char Listing[ 0x280000 ]; +unsigned char BufFile[ 0x10000 ]; +int TailleFic, CurLigne; + + +// +// Verifie si en-tete AMSDOS est valide +// +bool CheckAmsdos( unsigned char * Buf ) { + int i, Checksum = 0; + bool ModeAmsdos = false; + unsigned short CheckSumFile; + CheckSumFile = Buf[ 0x43 ] + Buf[ 0x43 +1 ] *256; + for ( i = 0; i < 67; i++ ) + Checksum += Buf[ i ]; + + if ( ( CheckSumFile == ( unsigned short )Checksum ) && Checksum ) + ModeAmsdos = true; + + return( ModeAmsdos ); +} + + + +// +// Cre une en-tte AMSDOS par dfaut +// +StAmsdos * CreeEnteteAmsdos( char * NomFic, unsigned short Longueur ) { + static char NomReel[ 256 ]; + static StAmsdos Entete; + static char Nom[ 12 ]; + int i; + + strcpy( NomReel, NomFic ); + memset( &Entete, 0, sizeof( Entete ) ); + memset( Nom, ' ', sizeof( Nom ) ); + char * p = NULL; + do { + p = strchr( NomReel, '/' ); //Sous linux c'est le / qu'il faut enlever ... + if ( p ) + strcpy( NomReel, ++p ); + } while( p ); + p = strchr( NomReel, '.' ); + if ( p ) + * p++ = 0; + + int l = strlen( NomReel ); + if ( l > 8 ) + l = 8; + + for ( int i = 0; i < l; i++ ) + Nom[ i ] = ( char )toupper( NomReel[ i ] ); + + if ( p ) + for ( i = 0; i < 3; i++ ) + Nom[ i + 8 ] = ( char )toupper( p[ i ] ); + + memcpy( Entete.FileName, Nom, 11 ); + Entete.Length = 0; //Non renseign par AMSDos !! + Entete.RealLength = Entete.LogicalLength = Longueur; + Entete.FileType = 2; //Fichier binaire + + SetChecksum(&Entete); + + return( &Entete ); +} + + +// +// Calcule et positionne le checksum AMSDOS +// +void SetChecksum( StAmsdos * pEntete ) { + int i, Checksum = 0; + unsigned char * p = ( unsigned char * )pEntete; + for ( i = 0; i < 67; i++ ) + Checksum += * (p+i); + + pEntete->CheckSum = ( unsigned short )Checksum; +} + + +// +// Effectue un "nettoyage" de l'en-tete Amsdos : +// remet a zero les octets inutilises +// +void ClearAmsdos( unsigned char * Buf ) { + if ( CheckAmsdos( Buf ) ) { + int i, Checksum = 0; + StAmsdos * pEntete = ( StAmsdos * )Buf; + memset( pEntete->Unused, 0, sizeof( pEntete->Unused ) ); + memset( pEntete->Unused2, 0, sizeof( pEntete->Unused2 ) ); + for ( i = 0; i < 67; i++ ) + Checksum += Buf[ i ]; + + Buf[ 0x43 ] = ( unsigned short )Checksum; + } +} + +// +// Recherche le plus petit secteur d'une piste +// +int DSK::GetMinSect( void ) { + int Sect = 0x100; + CPCEMUTrack * tr = ( CPCEMUTrack * )&ImgDsk[ sizeof( CPCEMUEnt ) ]; + for ( int s = 0; s < tr->NbSect; s++ ) + if ( Sect > tr->Sect[ s ].R ) + Sect = tr->Sect[ s ].R; + + return( Sect ); +} + + +// +// Retourne la position d'un secteur dans le fichier DSK +// +int DSK::GetPosData( int track, int sect, bool SectPhysique ) { + // Recherche position secteur + int Pos = sizeof( CPCEMUEnt ); + CPCEMUTrack * tr = ( CPCEMUTrack * )&ImgDsk[ Pos ]; + short SizeByte; + for ( int t = 0; t <= track; t++ ) { + Pos += sizeof( CPCEMUTrack ); + for ( int s = 0; s < tr->NbSect; s++ ) { + if ( t == track ) { + if ( ( ( tr->Sect[ s ].R == sect ) && SectPhysique ) + || ( ( s == sect ) && ! SectPhysique ) + ) + break; + } + SizeByte = tr->Sect[ s ].SizeByte ; + if (SizeByte) + Pos += SizeByte; + else + Pos += ( 128 << tr->Sect[ s ].N ); + } + } + return( Pos ); +} + + +// +// Recherche un bloc libre et le remplit +// +int DSK::RechercheBlocLibre( int MaxBloc ) { + for ( int i = 2; i < MaxBloc; i++ ) + if ( ! Bitmap[ i ] ) { + Bitmap[ i ] = 1; + return( i ); + } + return( 0 ); +} + + +// +// Recherche une entre de rpertoire libre +// +int DSK::RechercheDirLibre( void ) { + for ( int i = 0; i < 64; i++ ) { + StDirEntry * Dir = GetInfoDirEntry( i ); + if ( Dir->User == USER_DELETED ) + return( i ); + } + return( -1 ); +} + + +// +// Retourne les donnes "brutes" de l'image disquette +// +unsigned char * DSK::GetRawData( int Pos ) { + return( &ImgDsk[ Pos ] ); +} + + +// +// Ecriture de donnes "brutes" dans l'image disquette +// +void DSK::WriteRawData( int Pos, unsigned char * Data, int Longueur ) { + memcpy( &ImgDsk[ Pos ], Data, Longueur ); +} + + +// +// Retourne la taille du fichier image +// +int DSK::GetTailleDsk( void ) { + CPCEMUEnt * Infos = ( CPCEMUEnt * )ImgDsk; + int NbTracks = Infos->NbTracks; + int Pos = sizeof( CPCEMUEnt ); + CPCEMUTrack * tr = ( CPCEMUTrack * )&ImgDsk[ Pos ]; + for ( int t = 0; t < NbTracks; t++ ) { + Pos += sizeof( CPCEMUTrack ); + for ( int s = 0; s < tr->NbSect; s++ ) { + if ( tr->Sect[ s ].SizeByte ) + Pos += tr->Sect[ s ].SizeByte; + else + Pos += ( 128 << tr->Sect[ s ].N ); + } + } + return( Pos ); +} + + +// +// Retourne le nombre de pistes de la disquette +// +int DSK::GetNbTracks( void ) { + CPCEMUEnt * Infos = ( CPCEMUEnt * )ImgDsk; + return( Infos->NbTracks ); +} + + +// +// Lecture d'un bloc AMSDOS (1 block = 2 secteurs) +// +unsigned char * DSK::ReadBloc( int bloc ) { + static unsigned char BufBloc[ SECTSIZE * 2 ]; + int track = ( bloc << 1 ) / 9; + int sect = ( bloc << 1 ) % 9; + int MinSect = GetMinSect(); + if ( MinSect == 0x41 ) + track += 2; + else + if ( MinSect == 0x01 ) + track++; + + int Pos = GetPosData( track, sect + MinSect, true ); + memcpy( BufBloc, &ImgDsk[ Pos ], SECTSIZE ); + if ( ++sect > 8 ) { + track++; + sect = 0; + } + + Pos = GetPosData( track, sect + MinSect, true ); + memcpy( &BufBloc[ SECTSIZE ], &ImgDsk[ Pos ], SECTSIZE ); + return( BufBloc ); +} + + +// +// Formatter une piste +// +void DSK::FormatTrack( CPCEMUEnt * Infos, int t, int MinSect, int NbSect ) { + CPCEMUTrack * tr = ( CPCEMUTrack * )&ImgDsk[ sizeof( CPCEMUEnt ) + t * Infos->DataSize ]; + memset( &ImgDsk[ sizeof( CPCEMUEnt ) + + sizeof( CPCEMUTrack ) + + ( t * Infos->DataSize ) + ] + , 0xE5 + , 0x200 * NbSect + ); + strcpy( tr->ID, "Track-Info\r\n" ); + tr->Track = ( unsigned char )t; + tr->Head = 0; + tr->SectSize = 2; + tr->NbSect = ( unsigned char )NbSect; + tr->Gap3 = 0x4E; + tr->OctRemp = 0xE5; + int ss = 0; + // + // Gestion "entrelacement" des secteurs + // + for ( int s = 0; s < NbSect; ) { + tr->Sect[ s ].C = ( unsigned char )t; + tr->Sect[ s ].H = 0; + tr->Sect[ s ].R = ( unsigned char )( ss + MinSect ); + tr->Sect[ s ].N = 2; + tr->Sect[ s ].SizeByte = 0x200; + ss++; + if ( ++s < NbSect ) { + tr->Sect[ s ].C = ( unsigned char )t; + tr->Sect[ s ].H = 0; + tr->Sect[ s ].R = ( unsigned char )( ss + MinSect + 4 ); + tr->Sect[ s ].N = 2; + tr->Sect[ s ].SizeByte = 0x200; + s++; + } + } +} + + +// +// Ecriture d'un bloc AMSDOS (1 block = 2 secteurs) +// +void DSK::WriteBloc( int bloc, unsigned char BufBloc[ SECTSIZE * 2 ] ) { + int track = ( bloc << 1 ) / 9; + int sect = ( bloc << 1 ) % 9; + int MinSect = GetMinSect(); + if ( MinSect == 0x41 ) + track += 2; + else + if ( MinSect == 0x01 ) + track++; + + // + // Ajuste le nombre de pistes si dpassement capacit + // + CPCEMUEnt * Entete = ( CPCEMUEnt * )ImgDsk; + if ( track > Entete->NbTracks - 1 ) { + Entete->NbTracks = ( unsigned char )( track + 1 ); + FormatTrack( Entete, track, MinSect, 9 ); + } + + int Pos = GetPosData( track, sect + MinSect, true ); + memcpy( &ImgDsk[ Pos ], BufBloc, SECTSIZE ); + if ( ++sect > 8 ) { + track++; + sect = 0; + } + Pos = GetPosData( track, sect + MinSect, true ); + memcpy( &ImgDsk[ Pos ], &BufBloc[ SECTSIZE ], SECTSIZE ); +} + + +// +// Ecriture d'un secteur +// +void DSK::WriteSect( int Track, int Sect, unsigned char * Buff, int AmsdosMode ) { + int MinSect = AmsdosMode ? GetMinSect() : 0; + if ( ( MinSect == 0x41 ) && AmsdosMode ) + Track += 2; + else + if ( ( MinSect == 0x01 ) && AmsdosMode ) + Track++; + + int Pos = GetPosData( Track, Sect + MinSect, AmsdosMode ); + memcpy( &ImgDsk[ Pos ], Buff, SECTSIZE ); +} + + +// +// Lecture d'un secteur +// +unsigned char * DSK::ReadSect( int Track, int Sect, int AmsdosMode ) { + int MinSect = AmsdosMode ? GetMinSect() : 0; + if ( ( MinSect == 0x41 ) && AmsdosMode ) + Track += 2; + else + if ( ( MinSect == 0x01 ) && AmsdosMode ) + Track++; + + int Pos = GetPosData( Track, Sect + MinSect, AmsdosMode ); + return( &ImgDsk[ Pos ] ); +} + + +// +// Retourne les informations d'une piste +// +CPCEMUTrack * DSK::GetInfoTrack( int Track ) { + int Pos = sizeof( CPCEMUEnt ); + CPCEMUTrack * tr = ( CPCEMUTrack * )&ImgDsk[ Pos ]; + for ( int t = 0; t < Track; t++ ) { + Pos += sizeof( CPCEMUTrack ); + + for ( int s = 0; s < tr->NbSect; s++ ) { + if ( tr->Sect[ s ].SizeByte ) + Pos += tr->Sect[ s ].SizeByte; + else + Pos += ( 128 << tr->Sect[ s ].N ); + } + } + return( ( CPCEMUTrack * )&ImgDsk[ Pos ] ); +} + +// +// Remplit un "bitmap" pour savoir o il y a des fichiers sur la disquette +// Retourne galement le nombre de Ko utiliss sur la disquette +// +int DSK::FillBitmap( void ) { + int NbKo = 0; + + memset( Bitmap, 0, sizeof( Bitmap ) ); + Bitmap[ 0 ] = Bitmap[ 1 ] = 1; + for ( int i = 0; i < 64; i++ ) { + StDirEntry * Dir = GetInfoDirEntry( i ); + if ( Dir->User != USER_DELETED ) { + for ( int j = 0; j < 16; j++ ) { + int b = Dir->Blocks[ j ]; + if ( b > 1 && ( ! Bitmap[ b ] ) ) { + Bitmap[ b ] = 1; + NbKo++; + } + } + } + } + return( NbKo ); +} + + +// +// Positionne une entre dans le rpertoire +// +void DSK::SetInfoDirEntry( int NumDir, StDirEntry * Dir ) { + int MinSect = GetMinSect(); + int s = ( NumDir >> 4 ) + MinSect; + int t = ( MinSect == 0x41 ? 2 : 0 ); + if ( MinSect == 1 ) + t = 1; + + for (int i =0; i<16; i++) + memcpy( &ImgDsk[ ( ( NumDir & 15 ) << 5 ) + GetPosData( t, s, true ) ] + , Dir + , sizeof( StDirEntry ) + ); +} + + +// +// Vrifie l'existente d'un fichier, retourne l'indice du fichier si existe, +// -1 sinon +// +int DSK::FileExist( char * Nom ) { + int i; + for ( i = 0; i < 64; i++ ) { + StDirEntry * Dir = GetInfoDirEntry( i ); + for(int q=0;q<12;q++) + Dir->Nom[q]=Dir->Nom[q]&127; // Avoid missing hidden files + if ( Dir->User != USER_DELETED + && ! strncmp( Nom, ( char * )Dir->Nom, 11 ) // 11 = 8+3 car le point est enlev + ) + return( i ); + } + return( -1 ); +} + + +StDirEntry * DSK::GetNomDir( string NomFic ) { + static StDirEntry DirLoc; + int i; + + memset( &DirLoc, 0, sizeof( DirLoc ) ); + memset( DirLoc.Nom, ' ', 8 ); + memset( DirLoc.Ext, ' ', 3 ); + size_t p = NomFic.find('.'); + if ( p!=std::string::npos ) + { + NomFic.copy( DirLoc.Nom, std::min((int)p,8), 0); + p++; + NomFic.copy( DirLoc.Ext, std::min( (int)(NomFic.size()-p), 3 ), p ); + } + else + NomFic.copy( DirLoc.Nom, std::min((int)NomFic.size(), 8 ),0); + + for ( i = 0; i < 11; i++ ) + DirLoc.Nom[ i ] = ( unsigned char )toupper( DirLoc.Nom[ i ] ); + + return( &DirLoc ); +} + + +int DSK::FileIsIn( string FileName ) { + StDirEntry * DirLoc = GetNomDir( FileName ); + return FileExist( ( char*) DirLoc->Nom ); +} + +// +// Copie un fichier sur le DSK +// +// la taille est determine par le nombre de NbPages +// regarder pourquoi different d'une autre DSK +int DSK::CopieFichier( unsigned char * BufFile, char * NomFic, int TailleFic, int MaxBloc, int UserNumber, bool System_file, bool Read_only ) { + int j, l, Bloc, PosFile, NbPages = 0, PosDir, TaillePage; + FillBitmap(); + StDirEntry * DirLoc = GetNomDir( NomFic ); //Construit l'entre pour mettre dans le catalogue + for ( PosFile = 0; PosFile < TailleFic; ) { //Pour chaque bloc du fichier + PosDir = RechercheDirLibre(); //Trouve une entre libre dans le CAT + if ( PosDir != -1 ) { + DirLoc->User = UserNumber; //Remplit l'entre : User 0 + if(System_file) DirLoc->Nom[9]|=0x80; + if(Read_only) DirLoc->Nom[8]|=0x80; + DirLoc->NumPage = ( unsigned char )NbPages++; // Numro de l'entre dans le fichier + TaillePage = (TailleFic - PosFile + 127) >> 7 ; // Taille de la page (on arrondit par le haut) + if ( TaillePage > 128 ) // Si y'a plus de 16k il faut plusieurs pages + TaillePage = 128; + + DirLoc->NbPages = ( unsigned char )TaillePage; + l = ( DirLoc->NbPages + 7 ) >> 3; //Nombre de blocs=TaillePage/8 arrondi par le haut + memset( DirLoc->Blocks, 0, 16 ); + for ( j = 0; j < l; j++ ) { //Pour chaque bloc de la page + Bloc = RechercheBlocLibre( MaxBloc ); //Met le fichier sur la disquette + if ( Bloc ) { + DirLoc->Blocks[ j ] = ( unsigned char )Bloc; + WriteBloc( Bloc, &BufFile[ PosFile ] ); + PosFile += 1024; // Passe au bloc suivant + } + else + return( ERR_NO_BLOCK ); + + } + SetInfoDirEntry( PosDir, DirLoc ); + } + else + return( ERR_NO_DIRENTRY ); + } + return( ERR_NO_ERR ); +} + + +// +// Retourne une entre du rpertoire +// +StDirEntry * DSK::GetInfoDirEntry( int NumDir ) { + static StDirEntry Dir; + int MinSect = GetMinSect(); + int s = ( NumDir >> 4 ) + MinSect; + int t = ( MinSect == 0x41 ? 2 : 0 ); + if ( MinSect == 1 ) + t = 1; + + memcpy( &Dir + , &ImgDsk[ ( ( NumDir & 15 ) << 5 ) + GetPosData( t, s, true ) ] + , sizeof( StDirEntry ) + ); + return( &Dir ); +} + + +// +// Vrifier si DSK est "standard" (DATA ou VENDOR) +// +bool DSK::CheckDsk( void ) { + CPCEMUEnt * Infos = ( CPCEMUEnt * )ImgDsk; + if ( Infos->NbHeads == 1 ) { + int MinSectFirst = GetMinSect(); + if ( MinSectFirst != 0x41 && MinSectFirst != 0xC1 && MinSectFirst != 0x01 ) + { + cout << "DSK has wrong sector number!" << endl; + return( false ); + } + + + if ( Infos->NbTracks > 42 ) + Infos->NbTracks = 42; + + for ( int track = 0; track < Infos->NbTracks; track++ ) { + // Recherche position secteur + int Pos = sizeof( CPCEMUEnt ) + ( 0x1200 + sizeof( CPCEMUTrack ) ) * track; + CPCEMUTrack * tr = ( CPCEMUTrack * )&ImgDsk[ Pos ]; + + int MinSect = 0xFF, MaxSect = 0; + if ( tr->NbSect != 9 ) + { + cout << "Warning : track " << track <<" has "<NbSect<<" sectors ! (wanted 9)" << endl; + // return( false ); + } + for ( int s = 0; s < (int)tr->NbSect; s++ ) { + if ( MinSect > tr->Sect[ s ].R ) + MinSect = tr->Sect[ s ].R; + + if ( MaxSect < tr->Sect[ s ].R ) + MaxSect = tr->Sect[ s ].R; + } + if ( MaxSect - MinSect != 8 ) + { + cout << "Warning : trange sector numbering in track "<NbHeads << endl; + return( false ); +} + + +// +// Lire un fichier DSK +// +bool DSK::ReadDsk( std::string NomFic ) { + bool Ret = false; + CPCEMUEnt * Infos; + if(sizeof(CPCEMUEnt) != 0x100) cout << "INVALID DSK BUILD" << endl; + FILE* fp ; + + if ( (fp=fopen(NomFic.c_str(),"rb"))!=NULL ) { + fread(ImgDsk,sizeof(ImgDsk),1,fp); + Infos = ( CPCEMUEnt * )ImgDsk; + if ( isBigEndian( ) ) FixEndianDsk( false ); // fix endian for Big endianness machines (PPC) + if ( ! strncmp( Infos->debut, "MV -", 4 ) + || ! strncmp( Infos->debut, "EXTENDED CPC DSK", 16 ) + ) + Ret = true; + fclose(fp); + } + return( Ret ); +} + + +// +// Formatter une disquette +// +void DSK::FormatDsk( int NbSect, int NbTrack ) { + CPCEMUEnt * Infos = ( CPCEMUEnt * )ImgDsk; + + strcpy( Infos->debut, "MV - CPCEMU Disk-File\r\nDisk-Info\r\n" ); + Infos->DataSize = ( short )( sizeof( CPCEMUTrack ) + (0x200 * NbSect) ); + Infos->NbTracks = ( unsigned char ) NbTrack; + Infos->NbHeads = 1; + for ( int t = 0; t < NbTrack; t++ ) + FormatTrack( Infos, t, 0xC1, NbSect ); + + + FillBitmap(); +} + + + +// +// Modifie le endianness de la disquette +// +void DSK::FixEndianDsk( bool littleToBig) { + CPCEMUEnt * Infos = ( CPCEMUEnt * )ImgDsk; + //std::cerr<< "FixEndianDsk() Infos->DataSize : " << Infos->DataSize <DataSize = FIX_SHORT( Infos->DataSize ); + for ( int t = 0; t < Infos->NbTracks; t++ ) + FixEndianTrack( Infos, t, 9 ); + if ( littleToBig ) + Infos->DataSize = FIX_SHORT( Infos->DataSize ); + FillBitmap(); +} + +// +// Modifie le endianness de la piste +// +void DSK::FixEndianTrack( CPCEMUEnt * Infos, int t, int NbSect ) { + CPCEMUTrack *tr; + if ( Infos->DataSize != 0 ) + tr = ( CPCEMUTrack * )&ImgDsk[ sizeof( CPCEMUEnt ) + t * Infos->DataSize ]; + else { + int ExtendedDataSize = ImgDsk[ 0x34 + t ] *256; //case of a extended dsk image + tr = ( CPCEMUTrack * )&ImgDsk[ sizeof( CPCEMUEnt ) + t * ExtendedDataSize ]; + } + int ss = 0; + + // + // Gestion "entrelacement" des secteurs + // + for ( int s = 0; s < NbSect; ) { + tr->Sect[ s ].SizeByte = FIX_SHORT( tr->Sect[ s ].SizeByte ); + tr->Sect[ s ].Un1 = FIX_SHORT( tr->Sect[ s ].Un1 ); + ss++; + if ( ++s < NbSect ) { + tr->Sect[ s ].SizeByte = FIX_SHORT( tr->Sect[ s ].SizeByte ); + tr->Sect[ s ].Un1 = FIX_SHORT( tr->Sect[ s ].Un1 ); + s++; + } + } + tr->Unused = FIX_SHORT( tr->Unused ); +} + + +// +// Ecriture du fichier DSK +// +bool DSK::WriteDsk( string NomDsk ) { + CPCEMUEnt * Infos = ( CPCEMUEnt * )ImgDsk; + FILE* fp; + int Taille,Copie; + + + if ( (fp=fopen(NomDsk.c_str(),"wb+")) != NULL) { + if ( ! Infos->DataSize ) Infos->DataSize = 0x100 + SECTSIZE * 9; + Taille = Infos->NbTracks * Infos->DataSize + sizeof( * Infos ); + if ( isBigEndian() ) FixEndianDsk( true ) ; // Fix endianness for Big endian machines (PPC) + + if ( (Copie=(fwrite(ImgDsk,1,Taille,fp))) !=Taille ) ; + fclose(fp); + // in case of the same DSK image stay in memory + if ( isBigEndian() ) FixEndianDsk( false ) ; // unFix endianness for Big endian machines (PPC) + + return( true ); + } + return( false ); +} + + +void DSK::DskEndian() { + CPCEMUEnt * Infos = ( CPCEMUEnt * )ImgDsk; + for ( int i=1 ; i<(int)Infos->NbTracks ; i++) { + CPCEMUTrack * TrackData = GetInfoTrack( i ); + TrackData = CPCEMUTrackEndian ( TrackData ) ; + } + Infos = CPCEMUEntEndian ( Infos ) ; +} + + +StAmsdos* DSK::StAmsdosEndian ( StAmsdos * pEntete ){ + pEntete->Length = FIX_SHORT( pEntete->Length ); + pEntete->Adress = FIX_SHORT( pEntete->Adress ); + pEntete->LogicalLength = FIX_SHORT( pEntete->LogicalLength); + pEntete->EntryAdress = FIX_SHORT( pEntete->EntryAdress ); + pEntete->RealLength = FIX_SHORT( pEntete->RealLength ); + pEntete->CheckSum = FIX_SHORT( pEntete->CheckSum ) ; + return ( pEntete ); +} + + +CPCEMUEnt* DSK::CPCEMUEntEndian ( CPCEMUEnt* Infos ) { + Infos->DataSize = FIX_SHORT( Infos->DataSize ); + return (Infos); +} + + +CPCEMUTrack* DSK::CPCEMUTrackEndian ( CPCEMUTrack* tr ) { + for ( int i=0;i < (int)tr->NbSect ; i++) { + tr->Sect[i] = CPCEMUSectEndian( tr->Sect[i] ); + } + + return ( tr); + +} + + +CPCEMUSect DSK::CPCEMUSectEndian ( CPCEMUSect Sect) { + Sect.Un1 = FIX_SHORT( Sect.Un1 ); + Sect.SizeByte = FIX_SHORT( Sect.SizeByte ); + return (Sect); +} + +// Retourne le type de fichier sous forme de chaine +// +const char * DSK::GetType( int Langue, StAmsdos * Ams ) { + if ( CheckAmsdos( ( unsigned char * )Ams ) ) { + switch( Ams->FileType ) { + case 0 : // BASIC + return( "BASIC"); //GetTexteLoc( 22, Langue ) ); + + case 1 : // BASIC (P) + return( "BASIC(P)"); // GetTexteLoc( 23, Langue ) ); + + case 2 : // BINAIRE + return("BINAIRE"); // GetTexteLoc( 24, Langue ) ); + + case 3 : // BINAIRE (P) + return( "BINAIRE(P)"); //GetTexteLoc( 25, Langue ) ); + + default : + return( "INCONNU"); // GetTexteLoc( 26, Langue ) ); + } + } + return("ASCII"); // GetTexteLoc( 27, Langue ) ); +} + +char * DSK::GetEntryNameInCatalogue ( int num , char* Nom ) { + int PosItem[ 64 ]; + StDirEntry TabDir[ 64 ]; + + memset( PosItem, 0, sizeof( PosItem ) ); + + for ( int i = 0; i < 64; i++ ) + memcpy( &TabDir[ i ], GetInfoDirEntry( i ), sizeof( StDirEntry )); + + for ( int i = 0; i < 64; i++ ) { + SetInfoDirEntry( i, &TabDir[ i ] ); + + if ( TabDir[ i ].User != USER_DELETED && ! TabDir[ i ].NumPage && num == i) { + memcpy( Nom, TabDir[ i ].Nom, 8 ); + memcpy( &Nom[ 9 ], TabDir[ i ].Ext, 3 ); + Nom[ 8 ] = '.'; + Nom[ 12 ] = 0; + for ( int j = 0; j < 12; j++ ) + Nom[ j ] &= 0x7F; + for ( int j = 0; j < 12; j++ ) + if ( ! isprint( Nom[ j ] ) ) + Nom[ j ] = '?' ; + return Nom; + } + } + return Nom; +} + +char * DSK::GetEntrySizeInCatalogue ( int num , char* Size ) { + int PosItem[ 64 ]; + StDirEntry TabDir[ 64 ]; + + + memset( PosItem, 0, sizeof( PosItem ) ); + + for ( int i = 0; i < 64; i++ ) + memcpy( &TabDir[ i ], GetInfoDirEntry( i ), sizeof( StDirEntry )); + + for ( int i = 0; i < 64; i++ ) { + SetInfoDirEntry( i, &TabDir[ i ] ); + + if ( TabDir[ i ].User != USER_DELETED && ! TabDir[ i ].NumPage && num == i) { + int p = 0, t = 0; + do { + if ( TabDir[ p + i ].User == TabDir[ i ].User ) { + t += TabDir[ p + i ].NbPages; + } + p++; + } + while( TabDir[ p + i ].NumPage && ( p + i ) < 64 ); + sprintf( Size, "%d Ko", ( t + 7 ) >>3 ); + return Size; + } + } + return Size; +} + + +bool DSK::GetFileInDsk( char* path, int Indice ){ + int i = Indice; + char current[ 16 ]; + char NomIndice[ 16 ]; + int lMax = 0x1000000; + int cumul=0; + FILE* f; + StDirEntry TabDir[ 64 ]; + + if ( (f=fopen(path,"wb"))==NULL ) + return false; + + for ( int i = 0; i < 64; i++ ) + memcpy( &TabDir[ i ], GetInfoDirEntry( i ), sizeof( StDirEntry )); + + + memset( NomIndice, 0 , sizeof( NomIndice ) ); + strncpy( NomIndice, GetNomAmsdos( TabDir[ i ].Nom ), 16); + strncat( NomIndice, GetNomAmsdos( TabDir[ i ].Ext), 3); + + do + { + // Longueur du fichier + int l = ( TabDir[ i ].NbPages + 7 ) >> 3; + for ( int j = 0; j < l; j++ ) { + int TailleBloc = 1024; + unsigned char * p = ReadBloc( TabDir[ i ].Blocks[ j ] ); + int NbOctets = min( lMax, TailleBloc ); + if ( NbOctets > 0 ) { + fwrite(p,1,NbOctets,f); + cumul+=NbOctets; + } + lMax -= 1024; + } + memset( current , 0, sizeof( current ) ); + i++; + strncpy(current, GetNomAmsdos( TabDir[ i ].Nom ), 16 ); + strncat(current, GetNomAmsdos( TabDir[ i ].Ext ), 3); + + if ( i > 64 ) return false; + }while (! strncmp( NomIndice, current , max( strlen( NomIndice ), strlen( current ) ))); + + fclose (f); + return true; +} + + +bool DSK::PutFileInDsk( string Masque ,int TypeModeImport ,int loadAdress, int exeAdress, int UserNumber, bool System_file, bool Read_only ) { + static unsigned char Buff[ 0x20000 ]; + static char *cFileName; + unsigned long Lg; + bool ret; + FILE* Hfile; + if ( NULL==(cFileName = (char*)malloc(16*sizeof(char))) ) + return false; + + cFileName = GetNomAmsdos((char *)Masque.c_str()); + if (( Hfile = fopen(Masque.c_str(),"rb")) == NULL ) return false; + Lg=fread(Buff,1, 0x20000 ,Hfile); + fclose( Hfile ); + bool AjouteEntete = false; + StAmsdos * e = ( StAmsdos * )Buff; + // Attention : longueur > 64Ko ! + if ( Lg > 0x10080 ) { + free(cFileName); + return false; + } + + // + // Regarde si le fichier contient une en-tete ou non + // + bool IsAmsdos = CheckAmsdos( Buff ); + + if ( ! IsAmsdos ) { + // Creer une en-tete amsdos par defaut + cout << "Cration automatique d'une en-tte pour le fichier ...\n"; + e = CreeEnteteAmsdos( cFileName, ( unsigned short )Lg ); + if ( loadAdress != 0) + { + e->Adress = (unsigned short)loadAdress; + TypeModeImport = MODE_BINAIRE; + } + if ( exeAdress != 0 ) + { + e->EntryAdress = (unsigned short)exeAdress; + TypeModeImport = MODE_BINAIRE; + } + // Il faut recalculer le checksum en comptant es adresses ! + SetChecksum(e); + // fix the endianness of the input file + if ( isBigEndian() ) e = StAmsdosEndian(e); + } + else + cout << "Le fichier a dj une en-tte\n"; + // + // En fonction du mode d'importation... + // + switch( TypeModeImport ) { + case MODE_ASCII : + // + // Importation en mode ASCII + // + if ( IsAmsdos ) { + // Supprmier en-tete si elle existe + memcpy( Buff, &Buff[ sizeof( StAmsdos ) ], Lg - sizeof( StAmsdos )); + Lg -= sizeof( StAmsdos ); + } + break; + + case MODE_BINAIRE : + // + // Importation en mode BINAIRE + // + + if ( ! IsAmsdos ) + // + // Indique qu'il faudra ajouter une en-tete + // + AjouteEntete = true; + break; + + } + + // + // Si fichier ok pour etre import + // + if ( AjouteEntete ) { + // Ajoute l'en-tete amsdos si necessaire + + memmove( &Buff[ sizeof( StAmsdos ) ], Buff, Lg ); + memcpy( Buff, e, sizeof( StAmsdos ) ); + Lg += sizeof( StAmsdos ); + } + + //if (MODE_BINAIRE) ClearAmsdos(Buff); //Remplace les octets inutiliss par des 0 dans l'en-tte + + if ( CopieFichier( Buff,cFileName,Lg,256, UserNumber, System_file, Read_only) != ERR_NO_ERR ) + ret = false; + else + ret = true; + + return ret; +} + + +bool DSK::OnViewFic(int nItem) { + int LongFic = 0; + memset( BufFile, 0, sizeof( BufFile ) ); + memset( Listing, 0, sizeof( Listing ) ); + char NomFic[ 16 ]; + char current[ 16 ]; + int i = nItem; + bool FirstBlock = true; + StDirEntry TabDir[ 64 ]; + + for ( int j = 0; j < 64; j++ ) + memcpy( &TabDir[ j ], GetInfoDirEntry( j ), sizeof( StDirEntry )); + + memset( NomFic, 0 , sizeof( NomFic ) ); + strncpy( NomFic, GetNomAmsdos( TabDir[ i ].Nom ), 16); + strncat( NomFic, GetNomAmsdos( TabDir[ i ].Ext), 3); + + int lMax = sizeof( BufFile ); + + TailleFic = 0; + + + do + { + // Longueur du fichier + int l = ( TabDir[ i ].NbPages + 7 ) >> 3; + for ( int j = 0; j < l; j++ ) { + int TailleBloc = 1024; + unsigned char * p = ReadBloc( TabDir[ i ].Blocks[ j ] ); + if ( FirstBlock ) { + if ( CheckAmsdos( p ) ) { + TailleFic = p[ 0x18 +1 ] *256 + p[ 0x18 ]; + TailleBloc -= sizeof( StAmsdos ); + memcpy( p , &p[ 0x80 ] , TailleBloc ); + } + FirstBlock = false; + + } + int NbOctets = min( lMax, TailleBloc ); + if ( NbOctets > 0 ) { + memcpy( &BufFile[ LongFic ], p, NbOctets ); + LongFic += NbOctets; + } + lMax -= 1024; + } + memset( current , 0, sizeof( current ) ); + i++; + strncpy(current, GetNomAmsdos( TabDir[ i ].Nom ), 16 ); + strncat(current, GetNomAmsdos( TabDir[ i ].Ext ), 3); + if ( i > 64 ) return false; + }while( ! strncmp( NomFic, current, max( strlen( current ), strlen( NomFic ) ) ) ); + + if ( TailleFic == 0 ) + TailleFic = LongFic; + return true; +} + + +bool DSK::Hexdecimal() { + + int TailleCourante=0; + char OffSet[ 7 ]; + const char * CodeHexa = "0123456789ABCDEF"; + + while (TailleCourante <= TailleFic ) { + // display the offset + memset( OffSet, 0 , 7 ); + snprintf( OffSet,6,"#%.4X:", TailleCourante ); + strcat( Listing, OffSet ); + strcat( Listing, " "); + char Ascii[ 18 ]; + char Hex[ 16 *3 +1 ]; + memset( Ascii, 0 , 18 ); + memset( Hex , 0 , ( 16*3 +1) ); + for ( int i=0; i<16 ; ++i ) { + unsigned char cur = BufFile[ TailleCourante + i ]; + // manage the ascii display + if ( cur > 32 && cur < 125 ) + Ascii[ i ] = cur; + else + Ascii[ i ] = '.'; + char Val[ 4 ]; + // manage the hexadeciaml display + Val[ 0 ] = CodeHexa[ cur >> 4 ]; + Val[ 1 ] = CodeHexa[ cur & 0x0F ]; + Val[ 2 ] = ' '; + Val[ 3 ] ='\0'; + strcat( Hex, Val ); + } + Ascii[ 16 ] = '\n'; + strcat( Listing, Hex ); + strcat( Listing, "| "); + strcat( Listing, Ascii ); + TailleCourante += 16; + } + + return true; +} + + +void DSK::RemoveFile ( int item ) { + char NomFic[ 16 ]; + int i = item; + StDirEntry TabDir[ 64 ]; + + for ( int j = 0; j < 64; j++ ) + memcpy( &TabDir[ j ], GetInfoDirEntry( j ), sizeof( StDirEntry )); + + strcpy( NomFic, GetNomAmsdos( TabDir[ i ].Nom ) ); + char *p ; + + do { + TabDir[ i ].User = USER_DELETED; + SetInfoDirEntry( i, &TabDir[ i ]); + p = GetNomAmsdos( TabDir[ ++i ].Nom) ; + } while ( ! strncmp( NomFic, p , max(strlen( p ), strlen( NomFic ) )) ); + + + return ; +} + + + +void DSK::RenameFile( int item , char *NewName) { + char NomFic[ 16 ]; + StDirEntry TabDir[ 64 ]; + StDirEntry DirLoc; + int c = item; + for ( int j = 0; j < 64; j++ ) + memcpy( &TabDir[ j ], GetInfoDirEntry( j ), sizeof( StDirEntry )); + + memset( DirLoc.Nom, ' ', 8); + memset( DirLoc.Ext, ' ', 3); + for ( int i=0; i<(int) strlen( NewName ) ; ++i) + NewName[ i ] = toupper( NewName[ i ] ); + + char *p = strchr( NewName, '.'); + + if ( p ) { + p++; + memcpy( DirLoc.Nom, NewName, p - NewName -1); + memcpy( DirLoc.Ext, p, std::min((int)strlen(p),3) ); + } + else { + memcpy( DirLoc.Nom, NewName, min( (int)strlen( NewName) , 8 ) ); + } + strcpy( NomFic, GetNomAmsdos( TabDir[ c ].Nom )); + + do { + memcpy( TabDir[ c ].Nom , DirLoc.Nom , 8 ); + memcpy( TabDir[ c ].Ext , DirLoc.Ext, 3 ); + SetInfoDirEntry( c, &TabDir[ c ]); + p = GetNomAmsdos( TabDir[ ++c ].Nom ); + }while (!strncmp( NomFic, p , max(strlen(p),strlen(NomFic)))); +} + + +std::string DSK::ReadDskDir( void ) { + StDirEntry TabDir[ 64 ]; + string catalogue; + for ( int i = 0; i < 64; i++ ) { + memcpy( &TabDir[ i ] + , GetInfoDirEntry( i ) + , sizeof( StDirEntry ) + ); + } + // Trier les fichiers + for ( int i = 0; i < 64; i++ ) { + // + // Afficher les fichiers non effacs + // + if ( TabDir[ i ].User != USER_DELETED && ! TabDir[ i ].NumPage ) { + char Nom[ 13 ]; + memcpy( Nom, TabDir[ i ].Nom, 8 ); + memcpy( &Nom[ 9 ], TabDir[ i ].Ext, 3 ); + Nom[ 8 ] = '.'; + Nom[ 12 ] = 0; + // + // Masquer les bits d'attributs + // + for ( int j = 0; j < 12; j++ ) + { + Nom[ j ] &= 0x7F; + + if ( ! isprint( Nom[ j ] ) ) + Nom[ j ] = '?' ; + } + + catalogue += Nom; + catalogue += " "; + ostringstream c; + c << (int)TabDir[i].User; + catalogue += c.str(); + // + // Calcule la taille du fichier en fonction du nombre de blocs + // + int p = 0, t = 0; + do { + if ( TabDir[ p + i ].User == TabDir[ i ].User ) + t += TabDir[ p + i ].NbPages; + p++; + } while( TabDir[ p + i ].NumPage && ( p + i ) < 64 ); + //string size = GetTaille( ( t + 7 ) >> 3 ); + //catalogue+= " : " + size + "\n"; + catalogue += "\n"; + + } + } + return catalogue; +} diff --git a/tools/iDSK/src/GestDsk.h b/tools/iDSK/src/GestDsk.h new file mode 100644 index 0000000..b825ab4 --- /dev/null +++ b/tools/iDSK/src/GestDsk.h @@ -0,0 +1,168 @@ +#ifndef GESTDSK_H +#define GESTDSK_H + +#include + +#define USER_DELETED 0xE5 + + +extern char Listing[ 0x280000 ]; +extern unsigned char BufFile[ 0x10000 ]; + + +extern int TailleFic, CurLigne; + +#pragma pack(1) //evite le padding des structures qui sont utilisées dans des memcpy par la suite + +// +// Structure d'une entree AMSDOS +// +typedef struct +{ + unsigned char UserNumber; // 00 User + unsigned char FileName[15]; // 01-0F Nom + extension + unsigned char BlockNum; // 10 Numéro du bloc (disquette) + unsigned char LastBlock; // 11 Flag "dernier bloc" bloc (disquette) + unsigned char FileType; // 12 Type de fichier + unsigned short Length; // 13-14 Longueur + unsigned short Adress; // 15-16 Adresse + unsigned char FirstBlock; // 17 Flag premier bloc de fichier (disquette) + unsigned short LogicalLength; // 18-19 Longueur logique + unsigned short EntryAdress; // 1A-1B Point d'entree + unsigned char Unused[0x24]; + unsigned short RealLength; // 40-42 Longueur reelle + unsigned char BigLength; // Longueur reelle (3 octets) + unsigned short CheckSum; // 43-44 CheckSum Amsdos + unsigned char Unused2[0x3B]; +} StAmsdos; + + +#define SECTSIZE 512 + + +typedef struct +{ + char debut[0x30]; // "MV - CPCEMU Disk-File\r\nDisk-Info\r\n" + unsigned char NbTracks; + unsigned char NbHeads; + unsigned short DataSize; // 0x1300 = 256 + ( 512 * nbsecteurs ) + unsigned char Unused[0xCC]; +} CPCEMUEnt; + + +typedef struct +{ + unsigned char C; // track + unsigned char H; // head + unsigned char R; // sect + unsigned char N; // size + short Un1; + short SizeByte; // Taille secteur en octets +} CPCEMUSect; + + +typedef struct +{ + char ID[0x10]; // "Track-Info\r\n" + unsigned char Track; + unsigned char Head; + short Unused; + unsigned char SectSize; // 2 + unsigned char NbSect; // 9 + unsigned char Gap3; // 0x4E + unsigned char OctRemp; // 0xE5 + CPCEMUSect Sect[29]; +} CPCEMUTrack; + +#ifdef __GNUC__ +#define PACK( __Declaration__ ) __Declaration__ __attribute__((__packed__)) +#else +#define PACK( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop) ) +#endif + +PACK(typedef struct +{ + unsigned char User; + char Nom[8]; + char Ext[3]; + unsigned char NumPage; + unsigned char Unused[2]; + unsigned char NbPages; + unsigned char Blocks[16]; +}) StDirEntry; + +#pragma pack() + +enum { ERR_NO_ERR = 0, ERR_NO_DIRENTRY, ERR_NO_BLOCK, ERR_FILE_EXIST }; + +bool CheckAmsdos( unsigned char * Buf ); +StAmsdos * CreeEnteteAmsdos( char * NomFic, unsigned short Length ); +void ClearAmsdos( unsigned char * Buf ); +void SetChecksum( StAmsdos * pEntete ); +bool CheckAmsdos( unsigned char * Buf ); + + +class DSK +{ + unsigned char ImgDsk[ 0x80000 ]; + unsigned char Bitmap[ 256 ]; + + unsigned char * GetRawData( int Pos ); + void WriteRawData( int Pos, unsigned char * Data, int Longueur ); + int GetNbTracks( void ); + void WriteBloc( int bloc, unsigned char * BufBloc ); + void WriteSect( int Track, int Sect, unsigned char * Buff, int AmsdosMode ); + unsigned char * ReadSect( int Track, int Sect, int AmsdosMode ); + CPCEMUTrack * GetInfoTrack( int Track ); + int FillBitmap( void ); + void DskEndian(); + CPCEMUEnt* CPCEMUEntEndian ( CPCEMUEnt* Infos ); + CPCEMUTrack* CPCEMUTrackEndian ( CPCEMUTrack* tr ); + CPCEMUSect CPCEMUSectEndian ( CPCEMUSect Sect); + const char * GetType( int Langue, StAmsdos * Ams ); + int GetMinSect( void ); + int GetPosData( int track, int sect, bool SectPhysique ); + int RechercheBlocLibre( int MaxBloc ); + void FormatTrack( CPCEMUEnt * Infos, int t, int MinSect, int NbSect ); + +public: + DSK(){} + DSK(const DSK& d) + { + for (int i=0; i< 0x80000; i++) + ImgDsk[i]=d.ImgDsk[i]; + for (int j=0; j< 256 ; j++ ) + Bitmap[j]=d.Bitmap[j]; + } + + ~DSK(){} + + int GetTailleDsk(); + StDirEntry * GetNomDir(std::string Nom ); + int CopieFichier( unsigned char * BufFile, char * NomFic, int TailleFic, int MaxBloc, int, bool,bool ); + bool WriteDsk( std::string NomDsk ); + unsigned char * ReadBloc( int bloc ); + bool ReadDsk( std::string NomFic ); + bool CheckDsk( void ); + int FileExist( char * Nom ); + StDirEntry * GetInfoDirEntry( int NumDir ); + int FileIsIn( std::string FileName ); + int RechercheDirLibre( void ); + void FormatDsk( int NbSect, int NbTrack ); + StAmsdos* StAmsdosEndian ( StAmsdos * pEntete ); + void SetInfoDirEntry( int NumDir, StDirEntry * Dir ); + char * GetEntryNameInCatalogue ( int num , char* Nom ); + char * GetEntrySizeInCatalogue ( int num , char* Size ); + bool GetFileInDsk( char* path, int Indice ); + bool PutFileInDsk( std::string Masque ,int TypeModeImport ,int loadAdress, int exeAdress, int,bool,bool ); + bool OnViewFic(int nItem); + bool Hexdecimal(); + void RemoveFile ( int item ); + void FixEndianDsk( bool LittleToBig ); + void FixEndianTrack( CPCEMUEnt * Infos, int t, int NbSect ); + void RenameFile( int item , char *NewName); + std::string ReadDskDir(void); + +}; + +#endif diff --git a/tools/iDSK/src/Main.cpp b/tools/iDSK/src/Main.cpp new file mode 100644 index 0000000..f8bcdce --- /dev/null +++ b/tools/iDSK/src/Main.cpp @@ -0,0 +1,284 @@ +#include +#include +#include +#include // pour contourner un bug de std::vector ... + +#include "getopt_pp.h" /* Command line handling */ + +using namespace std; + +#include "MyType.h" +#include "GestDsk.h" +#include "Outils.h" +#include "Main.h" +#include "endianPPC.h" +#include "ViewFile.h" + +int main(int argc, char** argv) { + bool IsDskLoc, IsDskSet, + ModeListDsk, ModeImportFile, + ModeRemoveFile, + ModeDisaFile, ModeListBasic, + ModeListDams,ModeListHex, + ModeGetFile, ModeNewDsk, Force_Overwrite, + Read_only, System_file; + + ModeListDsk = ModeImportFile = + ModeRemoveFile = ModeDisaFile = + ModeListBasic = ModeListDams = ModeListHex = ModeNewDsk = + ModeGetFile = IsDskLoc = IsDskSet = Force_Overwrite = Read_only = System_file = false ; + + string DskFile, AmsdosFile; + vector AmsdosFileList; + + int exeAdress=0,loadAdress=0,AmsdosType=1, UserNumber=0; + + DSK MyDsk; + + IsDsk = IsDskValid = false; + IsDskSaved = true; + + // Rcupration des arguments avec getopt_pp +{using namespace GetOpt; + GetOpt_pp opts(argc,argv); + + opts >> GlobalOption(DskFile); + if (DskFile != "") + IsDskSet = true; + + opts >> OptionPresent('l',"list",ModeListDsk) + + >> OptionPresent('i',"import",ModeImportFile) + >> Option('i',"import",AmsdosFileList) + + >> OptionPresent('r',"remove",ModeRemoveFile) + >> Option('r',"remove",AmsdosFileList) + + >> OptionPresent('n',"new",ModeNewDsk) + + >> OptionPresent('z',"disassemble",ModeDisaFile) + >> Option('z',"disassemble",AmsdosFileList) + + >> OptionPresent('b',"basic",ModeListBasic) + >> Option('b',"basic",AmsdosFileList) + + >> OptionPresent('d',"dams",ModeListDams) + >> Option('d',"dams",AmsdosFileList) + + >> OptionPresent('h',"hex",ModeListHex) + >> Option('h',"hex",AmsdosFileList) + + >> std::hex >> Option('e',"exec",exeAdress) + >> Option('c',"load",loadAdress) + >> std::dec >> Option('t',"type",AmsdosType) + + >> OptionPresent('g',"get",ModeGetFile) + >> Option('g',"get",AmsdosFileList) + + >> OptionPresent('f',"force",Force_Overwrite) + >> OptionPresent('o',"write-protect",Read_only) + >> OptionPresent('s',"system",System_file) + >> Option('u',"user",UserNumber) + ; + + if(opts.options_remain()) + { + cout << "Unhandled option ! Check the syntax." << endl; + exit(EXIT_FAILURE); + } + +}//namespace getopt + + if ( ! IsDskSet ) { + cerr << "You did not select a DSK file to work with !" << endl; + help(); + } + else cerr << "DSK : " << DskFile << endl; + + if ( ModeListBasic || ModeListHex || ModeListDams || ModeDisaFile ) + { + if ( ! MyDsk.ReadDsk(DskFile)) + { + cerr<< "Error reading file ("<< DskFile << ")."<::iterator iter=AmsdosFileList.begin(); iter!=AmsdosFileList.end(); iter++) + { + char* amsdosF = GetNomAmsdos(iter->c_str()); + cerr << "Amsdos file : " << amsdosF << endl; + if ( (Indice= MyDsk.FileIsIn( amsdosF ))<0) { + cerr << "Error: File "<< amsdosF << " not found."<< endl; + exit(EXIT_FAILURE); + } + MyDsk.OnViewFic(Indice); + + if ( ModeListBasic ) + cout << ViewBasic( ) << endl; + else if ( ModeListDams ) + cout << "Not yet coded ! Please try a newer version of iDSK ! Sorry !"<::iterator iter=AmsdosFileList.begin(); iter!=AmsdosFileList.end(); iter++) + { + string amsdosfile = GetNomAmsdos(iter->c_str()); + int Indice; + if ( ( Indice = MyDsk.FileIsIn( amsdosfile ) ) != -1 && !Force_Overwrite) { + cerr << "(" << amsdosfile <<") File exists, replace ? (Y/N) (try -f switch for autoreplace...):"; + string answer ; + cin >> answer; + if ( toupper(answer[0]) == 'Y') + MyDsk.RemoveFile(Indice); + else { + cerr<<"Import cancelled, dsk unchanged."<::iterator iter=AmsdosFileList.begin(); iter!=AmsdosFileList.end(); iter++) + { + char* amsdosF = GetNomAmsdos(iter->c_str()); + cerr << "Amsdos file : " << amsdosF << endl; + if ( (Indice= MyDsk.FileIsIn( amsdosF ))<0) { + cerr << "Error : file "<< amsdosF << " not found."<< endl; + exit(EXIT_FAILURE); + } + MyDsk.RemoveFile(Indice); + if ( MyDsk.WriteDsk ((char*)DskFile.c_str()) ) + cout << MyDsk.ReadDskDir(); + else cerr<< "Error writing file " << (*iter) << endl; + } + } + + if ( ModeGetFile ) { + if ( ! MyDsk.ReadDsk( (char*)DskFile.c_str() ) ) { + cerr<< "Error reading dskfile ("<< DskFile << ")."<::iterator iter=AmsdosFileList.begin(); iter!=AmsdosFileList.end(); iter++) + { + char* amsdosF = GetNomAmsdos(iter->c_str()); + cerr << "Fichier Amsdos : " << amsdosF << endl; + if ( (Indice= MyDsk.FileIsIn( amsdosF ))<0) { + cerr << "Error : file "<< amsdosF << " not found."<< endl; + exit(EXIT_FAILURE); + } + if ( ! MyDsk.GetFileInDsk((char*)(*iter).c_str(),Indice) ) { + cerr <<"System error : unable to copy ("< [OPTIONS] [files to process]" << endl; + cout << "OPTIONS : EXAMPLE" << endl; + cout << "-l : List disk catalog iDSK floppy.dsk -l" << endl; + cout << "-g : export ('Get') file iDSK floppy.dsk -g myprog.bas"< +#include +#include +using namespace std; +#include "Outils.h" + +// +// Initialise une chaine au format hexad�cimal en fonction de la valeur d'entr�e +// +void Hex( char Chaine[], int Valeur, int Digit ) +{ + static char TabDigit[ 17 ] = "0123456789ABCDEF"; + + while( Digit ) + * Chaine++ = TabDigit[ ( Valeur >> ( 4 * ( --Digit ) ) ) & 0x0F ]; +} + + +// +// Conversion hexa->d�cimal +// +int HexToDec( char * Valeur ) +{ + char * p = strchr( Valeur, 'X' ); + if ( p ) + Valeur = ++p; + + p = strchr( Valeur, 'x' ); + if ( p ) + Valeur = ++p; + + p = strchr( Valeur, '#' ); + if ( p ) + Valeur = ++p; + + p = strchr( Valeur, '$' ); + if ( p ) + Valeur = ++p; + + p = strchr( Valeur, '&' ); + if ( p ) + Valeur = ++p; + + int Ret = 0, i = 0; + while( Valeur[ i ] ) + { + Ret <<= 4; + char c = Valeur[ i++ ]; + if ( c >= '0' && c <= '9' ) + Ret += c - '0'; + else + Ret += ( c & 0x5F ) - 0x37; + } + return( Ret ); +} + + +// +// Conversion d'un secteur (512 octets) en affichage Hexa et ASCII +// +void SetBuffViewHexa( unsigned char * src, char * Hex, char * Ascii, unsigned short Offset, int AddOffset) +{ + const char * CodeHexa = "0123456789ABCDEF"; + int q = 0,i; + + // + // Parcourir les 512 octets de la source et remplir les buffers + // + for ( i = 0; i < 512; i++ ) + { + unsigned char b = * src++; + if ( b > 32 && b < 127 ) + { + Ascii[ i ] = b; + // cout << "b32:" << (int)b <<" Ascii["<> 12 ]; + Hex[ q++ ] = CodeHexa[ ( Offset >> 8 ) & 0x0F ]; + Hex[ q++ ] = CodeHexa[ ( Offset >> 4 ) & 0x0F ]; + Hex[ q++ ] = CodeHexa[ Offset & 0x0F ]; + Hex[ q++ ] = ':'; + } + Offset++; + Hex[ q++ ] = CodeHexa[ b >> 4 ]; + Hex[ q++ ] = CodeHexa[ b & 0x0F ]; + Hex[ q++ ] = ' '; + } + Hex[ q ] = 0; + Ascii[ i ] = 0; +} + + +// +// Retourne le num�ro d'user sous forme de chaine +// +char * GetUser( int u ) +{ + static char User[ 8 ]; + sprintf(User, "%d", u); + return( User); +} + + + +// +// Retourne la taille du fichier sous forme de chaine +// +char * GetTaille( int t ) +{ + static char Taille[ 16 ]; + + sprintf( Taille, "%d Ko", t ); + return( Taille ); +} + + +// +// Retourne le nom du fichier formatt� amsdos (8+3) +// +char * GetNomAmsdos(const char * AmsName ) +{ + // Extract the name (without directory components) + const char* lastSlash = strrchr(AmsName, '/'); + const char* lastBackslash = strrchr(AmsName, '\\'); + if (lastSlash > lastBackslash) + AmsName = lastSlash + 1; + else if (lastSlash < lastBackslash) + AmsName = lastBackslash + 1; + + static char NomAmsdos[ 16 ]; + int i; + + char * p = NomAmsdos; + for ( i = 0; i < 8; i++ ) { + if ( * AmsName != ' ' && *AmsName != '.' ) + * p++ = * AmsName++; + /*if ( * AmsName == '-' ) + * p++ = * AmsName++;*/ + } + + while( * AmsName != '.' && * AmsName ) + AmsName++; + + AmsName++; + + * p = 0; + strcat( NomAmsdos, "." ); + + for ( i = 0; * AmsName && i < 3; i++ ) + *++p = * AmsName++; + + * ++p = 0; + i = 0; + while( NomAmsdos[ i ] ) + NomAmsdos[ i++ ] &= 0x7F; + + return( NomAmsdos ); +} diff --git a/tools/iDSK/src/Outils.h b/tools/iDSK/src/Outils.h new file mode 100644 index 0000000..3e64dc4 --- /dev/null +++ b/tools/iDSK/src/Outils.h @@ -0,0 +1,19 @@ +#ifndef __OUTILS_H__ +#define __OUTILS_H__ + + +void Hex( char Chaine[], int Valeur, int Digit ); + +int HexToDec( char * Valeur ); + +void SetBuffViewHexa( unsigned char * src, char * Hex, char * Ascii,unsigned short Offset, int AddOffset); + +char * GetNomAmsdos( const char * AmsName ); + +char * GetUser( int u ); + +char * GetTaille( int t ); + + + +#endif diff --git a/tools/iDSK/src/ViewFile.cpp b/tools/iDSK/src/ViewFile.cpp new file mode 100644 index 0000000..9ad2de7 --- /dev/null +++ b/tools/iDSK/src/ViewFile.cpp @@ -0,0 +1,36 @@ +#include +using namespace std; +#include "GestDsk.h" +#include "Outils.h" +#include "Basic.h" +#include "Desass.h" +#include "Dams.h" +#include "endianPPC.h" +#include "ViewFile.h" + +string ViewDams( ) +{ + cerr << "Taille du fichier : " << TailleFic << endl; + Dams( BufFile, TailleFic , Listing ); + return Listing; + //cout << Listing << endl; +} + + +string ViewDesass( ) +{ + cerr << "Taille du fichier : " << TailleFic << endl; + Desass( BufFile, Listing, TailleFic ); + return Listing; + //cout << Listing << endl; +} +string ViewBasic( ) +{ + bool IsBasic=true; + //cout << "Entre Ici\n"; + cerr << "Taille du fichier : " << TailleFic << endl; + Basic( BufFile, Listing, IsBasic, true ); + //cout << Listing << endl; + return Listing; + +} diff --git a/tools/iDSK/src/ViewFile.h b/tools/iDSK/src/ViewFile.h new file mode 100644 index 0000000..fd9b645 --- /dev/null +++ b/tools/iDSK/src/ViewFile.h @@ -0,0 +1,13 @@ +#ifndef __VIEWFILE_H__ +#define __VIEWFILE_H__ + + + + +string ViewDams(); +string ViewLine(); +string ViewDesass(); +string ViewBasic(); + + +#endif diff --git a/tools/iDSK/src/endianPPC.cpp b/tools/iDSK/src/endianPPC.cpp new file mode 100644 index 0000000..7b51225 --- /dev/null +++ b/tools/iDSK/src/endianPPC.cpp @@ -0,0 +1,20 @@ +#include +#include +using namespace std; +#include "endianPPC.h" + +#ifndef _MSC_VER +#include +#include +#endif + +bool isBigEndian(void) +{ +#ifdef BYTE_ORDER + return BYTE_ORDER == BIG_ENDIAN; +#elif defined _MSC_VER + return true; // It doesn't run on anything except x86, right? +#else + return __BYTE_ORDER == __BIG_ENDIAN; +#endif +} diff --git a/tools/iDSK/src/endianPPC.h b/tools/iDSK/src/endianPPC.h new file mode 100644 index 0000000..9def637 --- /dev/null +++ b/tools/iDSK/src/endianPPC.h @@ -0,0 +1,22 @@ +#ifndef __ENDIANPPC_H__ +#define __ENDIANPPC_H__ + +/* macros convertion little endian convertion to big endian convertion */ + + +#define SWAP_2(x) ( (((x) & 0xff) << 8) | ((unsigned short)(x) >> 8) ) +#define SWAP_4(x) ( ((x) << 24) | \ + (((x) << 8) & 0x00ff0000) | \ + (((x) >> 8) & 0x0000ff00) | \ + ((x) >> 24) ) +#define FIX_SHORT(x) (*(unsigned short *)&(x) = SWAP_2(*(unsigned short *)&(x))) +#define FIX_INT(x) (*(unsigned int *)&(x) = SWAP_4(*(unsigned int *)&(x))) +#define FIX_FLOAT(x) FIX_INT(x) + + + +/* endianness test function */ + +bool isBigEndian(void); + +#endif diff --git a/tools/iDSK/src/getopt_pp.cpp b/tools/iDSK/src/getopt_pp.cpp new file mode 100644 index 0000000..b22c81f --- /dev/null +++ b/tools/iDSK/src/getopt_pp.cpp @@ -0,0 +1,307 @@ +/* +GetOpt_pp: Yet another C++ version of getopt. + This file is part of GetOpt_pp. + + Copyright (C) Daniel Gutson, FuDePAN 2007-2010 + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt in the root directory or + copy at http://www.boost.org/LICENSE_1_0.txt) + + GetOpt_pp 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT + SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include + +#if __APPLE__ +#include +#define environ (*_NSGetEnviron()) +#elif _WIN32 +#include +#define environ _environ +#else +#include +#endif + +#include "getopt_pp.h" + +namespace GetOpt +{ + +GETOPT_INLINE Token* GetOpt_pp::_add_token(const std::string& value, Token::Type type) +{ + Token* const ret = new Token(value, type); + if (_first_token == NULL) + _first_token = ret; + else + _last_token->link_to(ret); + _last_token = ret; + return ret; +} + +GETOPT_INLINE void GetOpt_pp::_init_flags() +{ + std::stringstream ss; + _flags = ss.flags(); +} + +GETOPT_INLINE void GetOpt_pp::_parse_sub_file(const std::string& file) +{ + std::ifstream ifile(file.c_str()); + if (!ifile) + throw OptionsFileNotFoundEx(file); + + std::vector args; + std::string arg; + + while (ifile >> arg) + args.push_back(arg); + + _parse(args); +} + +GETOPT_INLINE void GetOpt_pp::_parse(const std::vector& args) +{ + bool any_option_processed = false; + const size_t argc = args.size(); + + size_t start = 0; + if ( _app_name.empty() ) + { + _app_name = args[0]; + start = 1; + } + + // parse arguments by their '-' or '--': + // (this will be a state machine soon) + for (size_t i = start; i < argc; i++) + { + const std::string& currentArg = args[i]; + + if (currentArg[0] == '-' && currentArg.size() > 1) + { + // see what's next, differentiate whether it's short or long: + if (currentArg[1] == '-') + { + if ( currentArg.size() > 2 ) + { + // long option + _longOps[currentArg.substr(2)].token = _add_token(currentArg.substr(2), Token::LongOption); + } + else + { + // it's the -- option alone + _longOps[currentArg].token = _add_token(currentArg, Token::GlobalArgument); + } + + any_option_processed = true; + } + else + { + // check if it is a negative number: rules + // * floating point negative numbers are straight classified as 'arguments' + // * integer negative numbers of more than 1 digit length are also 'arguments' + // * integer negatives of 1 digit length can be either arguments or short options. + // * anything else: short options. + int anInt; + float aFloat; + std::stringstream dummy; + if ( convert(currentArg, anInt, dummy.flags()) == _Option::OK ) + { + if ( currentArg.size() > 2 ) // if it's larger than -d (d=digit), then assume it's a negative number: + _add_token(currentArg, any_option_processed ? Token::UnknownYet : Token::GlobalArgument); + else // size == 2: it's a 1 digit negative number + _shortOps[currentArg[1]].token = _add_token(currentArg, Token::PossibleNegativeArgument); + } + else if ( convert(currentArg, aFloat, dummy.flags()) == _Option::OK ) + _add_token(currentArg, any_option_processed ? Token::UnknownYet : Token::GlobalArgument); + else + { + // short option + // iterate over all of them, keeping the last one in currentData + // (so the intermediates will generate 'existent' arguments, as of '-abc') + for( size_t j = 1; j < currentArg.size(); j++ ) + _shortOps[currentArg[j]].token = _add_token(std::string(currentArg, j, 1), Token::ShortOption); + } + + any_option_processed = true; + } + } + else if ( currentArg[0] == '@' && currentArg.size() > 1 ) + { + // suboptions file + _parse_sub_file(currentArg.substr(1)); + } + else + { + _add_token(currentArg, any_option_processed ? Token::UnknownYet : Token::GlobalArgument); + } + } + + _last = _Option::OK; // TODO: IMPROVE!! +} + +GETOPT_INLINE void GetOpt_pp::_parse_env() +{ + // this will be optimized in version 3 + std::string var_name; + std::string var_value; + size_t var = 0; + std::string::size_type pos; + OptionData* data; + + while (environ[var] != NULL) + { + var_name = environ[var]; + pos = var_name.find('='); + + if (pos != std::string::npos) + { + var_value = var_name.substr(pos + 1); + var_name = var_name.substr(0, pos); + + if (_longOps.find(var_name) == _longOps.end()) + { + data = &_longOps[var_name]; + data->token = _add_token(var_name, Token::LongOption); + data->flags = OptionData::Envir; + _add_token(var_value, Token::OptionArgument); + } + } + else + (data = &_longOps[var_name])->flags = OptionData::Envir; + + var++; + } +} + + +GETOPT_INLINE void GetOpt_pp::_argc_argv_to_vector(int argc, const char* const* const argv, std::vector& args) +{ + for (int i = 0; i < argc; i++) + args.push_back(argv[i]); +} + +GETOPT_INLINE GetOpt_pp::TokensDeleter::~TokensDeleter() +{ + Token* next; + Token* current(_first); + while (current != NULL) + { + next = current->next; + delete current; + current = next; + } +} + +GETOPT_INLINE GetOpt_pp::GetOpt_pp(int argc, const char* const* const argv) + : _exc(std::ios_base::goodbit), _first_token(NULL), _last_token(NULL), _tokens_deleter(_first_token) +{ + _init_flags(); + std::vector args; + _argc_argv_to_vector(argc, argv, args); + _parse(args); +} + +GETOPT_INLINE GetOpt_pp::GetOpt_pp(int argc, const char* const* const argv, _EnvTag) + : _first_token(NULL), _last_token(NULL), _tokens_deleter(_first_token) +{ + _init_flags(); + std::vector args; + _argc_argv_to_vector(argc, argv, args); + _parse(args); + _parse_env(); +} + +GETOPT_INLINE GetOpt_pp& GetOpt_pp::operator >> (const _Option& opt) throw(GetOptEx) +{ + if (_last != _Option::ParsingError) + { + _last = opt(_shortOps, _longOps, _first_token, _flags); + + switch (_last) + { + case _Option::OK: + break; + + case _Option::OptionNotFound: + if (_exc & std::ios_base::eofbit) + throw OptionNotFoundEx(); + break; + + case _Option::BadType: + if (_exc & std::ios_base::failbit) + throw InvalidFormatEx(); + break; + + case _Option::NoArgs: + if (_exc & std::ios_base::eofbit) + throw ArgumentNotFoundEx(); + break; + + case _Option::TooManyArgs: + if (_exc & std::ios_base::failbit) + throw TooManyArgumentsEx(); + break; + + case _Option::OptionNotFound_NoEx: + break; // Ok, it will be read by casting to bool + + case _Option::ParsingError: + break; // just to disable warning + } + } + else if (_exc & std::ios_base::failbit) + throw ParsingErrorEx(); + + return *this; +} + +GETOPT_INLINE GetOpt_pp& GetOpt_pp::operator >> (std::ios_base & (*iomanip)(std::ios_base&)) +{ + std::stringstream ss; + ss.flags(_flags); + _flags = (ss << iomanip).flags(); + return *this; +} + +GETOPT_INLINE bool GetOpt_pp::options_remain() const +{ + bool remain = false; + ShortOptions::const_iterator it = _shortOps.begin(); + while (it != _shortOps.end() && !remain) + { + remain = (it->second.flags == OptionData::CmdLine_NotExtracted); + ++it; + } + + if (!remain) + { + LongOptions::const_iterator it = _longOps.begin(); + while (it != _longOps.end() && !remain) + { + remain = (it->second.flags == OptionData::CmdLine_NotExtracted); + ++it; + } + } + + if (!remain) + { + // check for the global arguments: + Token* token = _first_token; + while (!remain && token != NULL) + { + remain = (token->type == Token::GlobalArgument || token->type == Token::UnknownYet); + token = token->next; + } + } + + return remain; +} + +} diff --git a/tools/iDSK/src/getopt_pp.h b/tools/iDSK/src/getopt_pp.h new file mode 100644 index 0000000..e0f991a --- /dev/null +++ b/tools/iDSK/src/getopt_pp.h @@ -0,0 +1,745 @@ +/* +GetOpt_pp: Yet another C++ version of getopt. + This file is part of GetOpt_pp. + + Copyright (C) Daniel Gutson, FuDePAN 2007-2010 + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt in the root directory or + copy at http://www.boost.org/LICENSE_1_0.txt) + + GetOpt_pp 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT + SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#ifndef GETOPT_PP_H +#define GETOPT_PP_H + +#include +#include // candidate to be removed +#include +#include +#include + +/* + DESIGN GOALS: + - EASY to use + - EASY to learn + - mimc STL's streams + - EASY to extend +*/ + +#ifndef GETOPT_INLINE +# define GETOPT_INLINE +#endif + +namespace GetOpt +{ + +struct Token +{ + enum Type + { + ShortOption, + LongOption, + GlobalArgument, + GlobalArgumentUsed, // already read, skip in the next read + OptionArgument, + PossibleNegativeArgument, + UnknownYet // can be a global option, or an option of the previous one + }; + + Type type; + std::string value; + Token* next; + + Token(const std::string& value, Type type = UnknownYet) + : type(type), value(value), next(NULL) + {} + + bool is_last() const + { + return next == NULL; + } + + void link_to(Token* new_next) + { + next = new_next; + } + + Token* get_next_option_argument() const + { + if (is_last()) + return NULL; + else + { + if (next->type == UnknownYet || next->type == OptionArgument || next->type == PossibleNegativeArgument) + return next; + else + return NULL; + } + } +}; + +struct OptionData +{ + enum _Flags + { + CmdLine_NotExtracted, + CmdLine_Extracted, + Envir + }; + + _Flags flags; + Token* token; + OptionData() : flags(CmdLine_NotExtracted) {} +}; + +typedef std::map LongOptions; +typedef std::map ShortOptions; + + +struct _Option +{ + enum Result + { + OK, + ParsingError, + OptionNotFound, + BadType, + NoArgs, + TooManyArgs, + OptionNotFound_NoEx + }; + + virtual Result operator()(ShortOptions& short_ops, LongOptions& long_ops, Token* first, std::ios::fmtflags flags) const = 0; + virtual ~_Option() {} + + static const char NO_SHORT_OPT = 0; +protected: + static void setTokenAsUsed(Token* token, ShortOptions& short_ops, Token::Type usedAs) + { + if (token->type == Token::PossibleNegativeArgument) + short_ops.erase(token->value[1]); + + token->type = usedAs; + } +}; + +template inline _Option::Result convert(const std::string& s, T& result, std::ios::fmtflags flags) +{ + std::stringstream ss; + ss.clear(); + ss.flags(flags); + ss << s; + ss >> result; + if (ss.fail() || !ss.eof()) + return _Option::BadType; + else + return _Option::OK; +} + +template <> inline _Option::Result convert(const std::string& s, std::string& result, std::ios::fmtflags /*flags*/) +{ + result = s; + return _Option::OK; +} + + +template class _OptionTBase : public _Option +{ + const char short_opt; + const std::string long_opt; +protected: + T& target; + virtual Result _assign(Token* token, std::ios::fmtflags flags, ShortOptions& short_ops) const = 0; + +public: + _OptionTBase(const _OptionTBase& other) + : _Option(), short_opt(other.short_opt), long_opt(other.long_opt), target(other.target) + {} + + _OptionTBase(char short_opt, const std::string& long_opt, T& target) + : short_opt(short_opt), long_opt(long_opt), target(target) + {} + + virtual Result operator()(ShortOptions& short_ops, LongOptions& long_ops, Token* /*first*/, std::ios::fmtflags flags) const + { + Result ret = OptionNotFound; + ShortOptions::iterator it; + if (short_opt == _Option::NO_SHORT_OPT) + it = short_ops.end(); + else + it = short_ops.find(short_opt); + + if (it != short_ops.end()) + { + it->second.flags = OptionData::CmdLine_Extracted; + ret = _assign(it->second.token, flags, short_ops); + } + else if (!long_opt.empty()) + { + LongOptions::iterator it = long_ops.find(long_opt); + if (it != long_ops.end()) + { + it->second.flags = OptionData::CmdLine_Extracted; + ret = _assign(it->second.token, flags, short_ops); + } + } + + return ret; + } +}; + + +template class _OptionT : public _OptionTBase +{ +protected: + virtual _Option::Result _assign(Token* token, std::ios::fmtflags flags, ShortOptions& short_ops) const + { + Token* const option_token = token->get_next_option_argument(); + if (option_token == NULL) + return _Option::NoArgs; + else + { + this->setTokenAsUsed(option_token, short_ops, Token::OptionArgument); + return convert(option_token->value, this->target, flags); + } + } +public: + _OptionT(const _OptionT& other) + : _OptionTBase(other) + {} + + _OptionT(char short_opt, const std::string& long_opt, T& target) + : _OptionTBase(short_opt, long_opt, target) + {} + +}; + +template class _OptionT > : public _OptionTBase > +{ +protected: + virtual _Option::Result _assign(Token* token, std::ios::fmtflags flags, ShortOptions& short_ops) const + { + Token* option_token = token->get_next_option_argument(); + if (option_token != NULL) + { + _Option::Result result; + //OptionArgs::const_iterator it = args.begin(); + T temp; + + do + { + this->setTokenAsUsed(option_token, short_ops, Token::OptionArgument); + result = convert(option_token->value, temp, flags); + if (result == _Option::OK) + this->target.push_back(temp); + + option_token = option_token->get_next_option_argument(); + } + while (option_token != NULL && result == _Option::OK); + + return result; + } + else + return _Option::NoArgs; + } + +public: + _OptionT(const _OptionT >& other) + : _OptionTBase >(other) + {} + + _OptionT(char short_opt, const std::string& long_opt, std::vector& target) + : _OptionTBase >(short_opt, long_opt, target) + {} +}; + + +template +class _DefValOption : public BaseOption +{ + const T default_value; +public: + + _DefValOption(const _DefValOption& other) + : BaseOption(other), default_value(other.default_value) + {} + + _DefValOption(char short_opt, const std::string& long_opt, T& target, const T& default_value) + : BaseOption(short_opt, long_opt, target), default_value(default_value) + {} + + virtual _Option::Result operator()(ShortOptions& short_ops, LongOptions& long_ops, Token* first, std::ios::fmtflags flags) const + { + _Option::Result ret = BaseOption::operator()(short_ops, long_ops, first, flags); + + if (ret == _Option::OptionNotFound) + { + this->target = default_value; + ret = _Option::OK; + } + + return ret; + } +}; + +template +class _GlobalOption : public _Option +{ + T& target; + virtual Result operator()(ShortOptions& short_ops, LongOptions& long_ops, Token* first, std::ios::fmtflags flags) const + { + // find first token GlobalArgument or UnknownYet (candidate) or PossibleNegativeArgument (candidate too) + Token* token(first); + bool found(false); + while (token != NULL && !found) + { + found = (token->type == Token::GlobalArgument || token->type == Token::UnknownYet || token->type == Token::PossibleNegativeArgument); + if (!found) + token = token->next; + } + if (found) + { + this->setTokenAsUsed(token, short_ops, Token::GlobalArgumentUsed); + return convert(token->value, target, flags); + } + else + return OptionNotFound; + } +public: + _GlobalOption(const _GlobalOption& other) + : target(other.target) + {} + + _GlobalOption(T& target) + : target(target) + {} +}; + +template +class _GlobalOption > : public _Option +{ + std::vector& target; + virtual Result operator()(ShortOptions& short_ops, LongOptions& /*long_ops*/, Token* first, std::ios::fmtflags flags) const + { + // find first token GlobalArgument or UnknownYet (candidate) or PossibleNegativeArgument (candidate too) + Token* token(first); + bool found_any(false); + T tmp; + Result res(OK); + + while (token != NULL && res == OK) + { + if (token->type == Token::GlobalArgument || token->type == Token::UnknownYet || token->type == Token::PossibleNegativeArgument) + { + res = convert(token->value, tmp, flags); + if (res == OK) + { + this->setTokenAsUsed(token, short_ops, Token::GlobalArgumentUsed); + found_any = true; + target.push_back(tmp); + } + } + token = token->next; + } + if (res == OK) + { + if (found_any) + return res; + else + return OptionNotFound; + } + else + return res; + } +public: + _GlobalOption(const _GlobalOption >& other) + : target(other.target) + {} + + _GlobalOption(std::vector& target) + : target(target) + {} +}; + +template +inline _OptionT Option(char short_opt, const std::string& long_opt, T& target) +{ + return _OptionT(short_opt, long_opt, target); +} + +template +inline _OptionT Option(char short_opt, T& target) +{ + return _OptionT(short_opt, std::string(), target); +} + +// LongOpt only +template +inline _OptionT Option(const std::string& long_opt, T& target) +{ + return _OptionT(_Option::NO_SHORT_OPT, long_opt, target); +} + +// Defaulted version +template +inline _DefValOption > +Option(char short_opt, const std::string& long_opt, T& target, const T& def) +{ + return _DefValOption >(short_opt, long_opt, target, def); +} + +template +inline _DefValOption > Option(char short_opt, T& target, const T& def) +{ + return _DefValOption >(short_opt, std::string(), target, def); +} + +// no short opt. +template +inline _DefValOption > +Option(const std::string& long_opt, T& target, const T& def) +{ + return _DefValOption >(_Option::NO_SHORT_OPT, long_opt, target, def); +} + +// Defaults for strings: +inline _DefValOption > +Option(char short_opt, const std::string& long_opt, std::string& target, const char* def) +{ + return _DefValOption >(short_opt, long_opt, target, def); +} + +inline _OptionT Option(char short_opt, std::string& target, const char* def) +{ + return _DefValOption >(short_opt, std::string(), target, def); +} + +// no short opt. +inline _DefValOption > +Option(const std::string& long_opt, std::string& target, const char* def) +{ + return _DefValOption >(_Option::NO_SHORT_OPT, long_opt, target, def); +} + +// Global Option: +template +inline _GlobalOption GlobalOption(T& target) +{ + return _GlobalOption(target); +} + +class OptionPresent : public _Option +{ + const char short_opt; + const std::string long_opt; + bool* const present; +public: + // two combinations: with/without target, and with/without long opt. + + // WITH long_opt: + OptionPresent(char short_opt, const std::string& long_opt, bool& present) + : short_opt(short_opt), long_opt(long_opt), present(&present) + {} + + OptionPresent(char short_opt, const std::string& long_opt) + : short_opt(short_opt), long_opt(long_opt), present(NULL) + {} + + // WITHOUT long_opt: + OptionPresent(char short_opt, bool& present) + : short_opt(short_opt), present(&present) + {} + + OptionPresent(char short_opt) + : short_opt(short_opt), present(NULL) + {} + + // WITHOUT short_opt + OptionPresent(const std::string& long_opt, bool& present) + : short_opt(_Option::NO_SHORT_OPT), long_opt(long_opt), present(&present) + {} + + OptionPresent(const std::string& long_opt) + : short_opt(_Option::NO_SHORT_OPT), long_opt(long_opt), present(NULL) + {} +protected: + virtual Result operator()(ShortOptions& short_ops, LongOptions& long_ops, Token* /*first*/, std::ios::fmtflags /*flags*/) const + { + bool found; + ShortOptions::iterator it = short_ops.find(short_opt); + + found = (it != short_ops.end()); + if (found) + { + it->second.flags = OptionData::CmdLine_Extracted; + } + else if (!long_opt.empty()) + { + LongOptions::iterator it = long_ops.find(long_opt); + found = (it != long_ops.end()); + if (found) + { + it->second.flags = OptionData::CmdLine_Extracted; + } + } + + if (present != NULL) + { + *present = found; + return OK; + } + else + { + return found ? OK : OptionNotFound_NoEx; + } + } +}; + +class GetOptEx : public std::exception {}; +struct ParsingErrorEx : GetOptEx {}; +struct InvalidFormatEx : GetOptEx {}; +struct ArgumentNotFoundEx : GetOptEx {}; +struct TooManyArgumentsEx : GetOptEx {}; +struct OptionNotFoundEx : GetOptEx {}; +struct TooManyOptionsEx : GetOptEx {}; +struct OptionsFileNotFoundEx : GetOptEx +{ + const std::string targetFile; + OptionsFileNotFoundEx(const std::string& file) : targetFile(file) {} + ~OptionsFileNotFoundEx() throw() {} +}; + +enum _EnvTag +{ + Include_Environment +}; + +class GetOpt_pp +{ + ShortOptions _shortOps; + LongOptions _longOps; + std::ios_base::iostate _exc; + _Option::Result _last; + std::ios::fmtflags _flags; + std::string _app_name; + Token* _first_token; + Token* _last_token; + + class TokensDeleter + { + Token*& _first; + public: + TokensDeleter(Token*& first) : _first(first) {} + + GETOPT_INLINE ~TokensDeleter(); + }; + + TokensDeleter _tokens_deleter; + + GETOPT_INLINE Token* _add_token(const std::string& value, Token::Type type); + GETOPT_INLINE void _init_flags(); + GETOPT_INLINE void _parse(const std::vector& args); + GETOPT_INLINE void _parse_env(); + static GETOPT_INLINE void _argc_argv_to_vector(int argc, const char* const* const argv, std::vector& args); + GETOPT_INLINE void _parse_sub_file(const std::string& file); +public: + GETOPT_INLINE GetOpt_pp(int argc, const char* const* const argv); + GETOPT_INLINE GetOpt_pp(int argc, const char* const* const argv, _EnvTag); + + std::ios_base::iostate exceptions() const + { + return _exc; + } + void exceptions(std::ios_base::iostate except) + { + _exc = except; + } + void exceptions_all() + { + _exc = std::ios_base::failbit | std::ios_base::eofbit; + } + + operator bool() const + { + return _last == _Option::OK; + } + + GETOPT_INLINE bool options_remain() const; + + void end_of_options() const throw(GetOptEx) + { + if (options_remain() && (_exc & std::ios_base::eofbit)) + throw TooManyOptionsEx(); + } + + std::ios::fmtflags flags() const + { + return _flags; + } + void flags(std::ios::fmtflags flags) + { + _flags = flags; + } + + const std::string& app_name() const + { + return _app_name; + } + + GETOPT_INLINE GetOpt_pp& operator >> (const _Option& opt) throw(GetOptEx); + + GETOPT_INLINE GetOpt_pp& operator >> (std::ios_base& (*iomanip)(std::ios_base&)); + + // Alternative to manipulators, for those who don't like them: the 'getopt' method :) + // Combination 1: with long option: + template inline T getopt(char short_opt, const std::string& long_opt) throw(GetOptEx) + { + T result; + operator >> (Option(short_opt, long_opt, result)); + return result; + } + + template inline T getopt(char short_opt, const std::string& long_opt, const T& def_value) + { + T result; + operator >> (Option(short_opt, long_opt, result, def_value)); + return result; + } + + // Combination 2: without long option: + template inline T getopt(char short_opt) throw(GetOptEx) + { + T result; + operator >> (Option(short_opt, result)); + return result; + } + + template inline T getopt(char short_opt, const T& def_value) + { + T result; + operator >> (Option(short_opt, result, def_value)); + return result; + } + + struct ItCtorData + { + ShortOptions::const_iterator short_iter; + LongOptions::const_iterator long_iter; + GetOpt_pp* getopt_pp; + }; + + template + class _iterator + { + typename Container::const_iterator _it; + GetOpt_pp* _getopt_pp; + public: + _iterator(const ItCtorData& ctor_data) + { + _it = Adapter::adapt(ctor_data); + _getopt_pp = ctor_data.getopt_pp; + } + + _iterator() : _getopt_pp(NULL) + {} + + _iterator& operator = (const _iterator& other) + { + _it = other._it; + _getopt_pp = other._getopt_pp; + return *this; + } + + bool operator != (const _iterator& other) const + { + return _it != other._it; + } + + OptionType option() const + { + return _it->first; + } + OptionType operator*() const + { + return option(); + } + + _iterator& operator ++() + { + ++_it; + return *this; + } + + template + GetOpt_pp& operator >> (T& t) + { + Adapter::extract(t, *_getopt_pp, option()); + return *_getopt_pp; + } + }; + + ItCtorData begin() + { + ItCtorData ret; + ret.short_iter = _shortOps.begin(); + ret.long_iter = _longOps.begin(); + ret.getopt_pp = this; + return ret; + } + + ItCtorData end() + { + ItCtorData ret; + ret.short_iter = _shortOps.end(); + ret.long_iter = _longOps.end(); + ret.getopt_pp = this; + return ret; + } + + struct ShortAdapter + { + static ShortOptions::const_iterator adapt(const ItCtorData& data) + { + return data.short_iter; + } + + template + static void extract(T& t, GetOpt_pp& getopt_pp, char option) + { + getopt_pp >> Option(option, t); + } + }; + + struct LongAdapter + { + static LongOptions::const_iterator adapt(const ItCtorData& data) + { + return data.long_iter; + } + + template + static void extract(T& t, GetOpt_pp& getopt_pp, const std::string& option) + { + getopt_pp >> Option('\0', option, t); + } + }; + + typedef _iterator short_iterator; + typedef _iterator long_iterator; +}; + +class Environment +{ + // Coming soon! +}; + +} + +#endif diff --git a/tools/img2f.py b/tools/img2f.py new file mode 100755 index 0000000..23ac1a7 --- /dev/null +++ b/tools/img2f.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python + +__version__ = "1.0" + +from argparse import ArgumentParser +from PIL import Image + +def main(): + + parser = ArgumentParser(description="Image to cpcrslib font", + epilog="Copyright (C) 2015 Juan J Martinez ", + ) + + parser.add_argument("--version", action="version", version="%(prog)s " + __version__) + parser.add_argument("image", help="image to convert") + parser.add_argument("id", help="variable name") + parser.add_argument("--effect", dest="effect", action="store_true") + + args = parser.parse_args() + + try: + image = Image.open(args.image) + except IOError: + parser.error("failed to open the image") + + if image.mode != "P": + parser.error("not an indexed image (no palette)") + + (w, h) = image.size + data = image.getdata() + + out = [] + for y in range(0, h, 8): + for x in range(0, w, 4): + for j in range(8): + row = 0 + for i in range(4): + if data[x + i + (j + y) * w] != 0: + if args.effect and j in (2, 3, 4, 5): + row |= 1 << (7 - ((i * 2) + 1)) + row |= 1 << (7 - (i * 2)) + out.append(row) + + data_out = "" + for part in range(0, len(out), 8): + if data_out: + data_out += ",\n" + data_out += ', '.join(["0x%02x" % b for b in out[part: part + 8]]) + + print("const unsigned char %s[] = {\n%s\n};\n" % (args.id, data_out)) + +if __name__ == "__main__": + main() + diff --git a/tools/img2sprite.py b/tools/img2sprite.py new file mode 100755 index 0000000..6463e0c --- /dev/null +++ b/tools/img2sprite.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python + +__version__ = "1.0" + +import sys +from argparse import ArgumentParser +from PIL import Image + +DEF_W = 8 +DEF_H = 16 + +def encode_byte(a, b): + return (a & 1) << 7 | (b & 1) << 6 \ + | (a & 4) << 3 | (b & 4) << 2 \ + | (a & 2) << 2 | (b & 2) << 1 \ + | (a & 8) >> 2 | (b & 8) >> 3 + +def main(): + + parser = ArgumentParser(description="Image cpcrslib sprite", + epilog="Copyright (C) 2015 Juan J Martinez ", + ) + + parser.add_argument("--version", action="version", version="%(prog)s " + __version__) + parser.add_argument("-i", "--id", dest="id", default="sprite", type=str, + help="variable name (default: sprite)") + parser.add_argument("--width", dest="w", default=DEF_W, type=int, + help="sprite width (default: %s)" % DEF_W) + parser.add_argument("--height", dest="h", default=DEF_H, type=int, + help="sprite height (default: %s)" % DEF_H) + parser.add_argument("--transparent-color", dest="tc", default=None, type=int, + help="palette index for the transparent color (default: None)") + parser.add_argument("-d", "--dimension", dest="dim", action="store_true", + help="include the sprite dimensions in the output") + parser.add_argument("-b", "--binary", dest="binary", action="store_true", + help="output binary instead of C code") + + + parser.add_argument("image", help="image to convert", nargs="?") + + args = parser.parse_args() + + if not args.image: + parser.error("required parameter: image") + + if args.tc: + try: + args.tc = int(args.tc) + if args.tc < 0 or args.tc > 15: + raise ValueError() + except ValueError: + parser.error("--transparent-color expects an integer in [0, 15]") + + try: + image = Image.open(args.image) + except IOError: + parser.error("failed to open the image") + + if image.mode != "P": + parser.error("not an indexed image (no palette)") + + (w, h) = image.size + + if w % args.w or h % args.h: + parser.error("%s size is not multiple of the image size" % args.image) + + data = image.getdata() + + out = [] + for x in range(0, w, args.w): + frame = [] + for y in range(h): # FIXME: different heights! + if args.dim: + out.extend([args.w // 2, args.h]) + for i in range(0, args.w, 2): + a = data[x + i + (y * w)] + b = data[x + i + 1 + (y * w)] + + if args.tc is not None: + mask_a = mask_b = 0 + if a == args.tc: + mask_a = 0xf + a = 0 + if b == args.tc: + mask_b = 0xf + b = 0 + frame.append(encode_byte(mask_a, mask_b)) + + frame.append(encode_byte(a, b)) + out.append(frame) + + if args.binary: + for frame in out: + sys.stdout.write(bytearray(frame)) + return + + frames = len(out) + + data_out = "" + for block in out: + if data_out: + data_out += ",\n" + data_out += "{" + for part in range(0, len(block), 4): + if data_out and data_out[-1] != "{": + data_out += ",\n" + data_out += ', '.join(["0x%02x" % b for b in block[part: part + 4]]) + data_out += "}" + + print("/* %sx%s (frames: %s, mask: %s, dim: %s) */" % (args.w, args.h, frames, args.tc is not None, args.dim)) + print("const unsigned char %s[%d][%d] = {\n%s\n};\n" % (args.id, len(out), len(out[0]), data_out)) + +if __name__ == "__main__": + main() + diff --git a/tools/map.py b/tools/map.py new file mode 100755 index 0000000..e5d3199 --- /dev/null +++ b/tools/map.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python + +__version__ = "1.0" + +import sys +from argparse import ArgumentParser +import json +import subprocess +from collections import defaultdict + +DEF_ROOM_WIDTH = 20 +DEF_ROOM_HEIGHT = 10 + +def find_name(data, name): + for item in data: + if item.get("name").lower() == name.lower(): + return item + raise ValueError("%r not found" % name) + +def main(): + + parser = ArgumentParser(description="Map importer", + epilog="Copyright (C) 2015 Juan J Martinez ", + ) + + parser.add_argument("--version", action="version", version="%(prog)s " + __version__) + parser.add_argument("--room-width", dest="rw", default=DEF_ROOM_WIDTH, type=int, + help="room width (default: %s)" % DEF_ROOM_WIDTH) + parser.add_argument("--room-height", dest="rh", default=DEF_ROOM_HEIGHT, type=int, + help="room height (default: %s)" % DEF_ROOM_HEIGHT) + parser.add_argument("-b", dest="bin", action="store_true", + help="output binary data (default: C code)") + parser.add_argument("--ucl", dest="ucl", action="store_true", + help="UCL compress (requires ucl binary in the path)") + parser.add_argument("map_json", help="Map to import") + parser.add_argument("id", help="variable name") + + args = parser.parse_args() + + with open(args.map_json, "rt") as fd: + data = json.load(fd) + + mh = data.get("height", 0) + mw = data.get("width", 0) + + if mh < args.rh or mh % args.rh: + parser.error("Map size in not multiple of the room size") + if mw < args.rw or mw % args.rw: + parser.error("Map size in not multiple of the room size") + + tilewidth = data["tilewidth"] + tileheight = data["tileheight"] + + tile_layer = find_name(data["layers"], "Map")["data"] + + def_tileset = find_name(data["tilesets"], "default") + tileprops = def_tileset.get("tileproperties", {}) + firstgid = def_tileset.get("firstgid") + + out = [] + for y in range(0, mh, args.rh): + for x in range(0, mw, args.rw): + current = [] + for j in range(args.rh): + for i in range(args.rw / 2): + a = (tile_layer[x + (i * 2) + (y + j) * mw] - firstgid) & 0b111 + if str(a) in tileprops and tileprops[str(a)].get("blocked"): + a |= 0b1000 + + b = (tile_layer[x + (i * 2) + 1 + (y + j) * mw] - firstgid) & 0b111 + if str(b) in tileprops and tileprops[str(b)].get("blocked"): + b |= 0b1000 + + current.append((a << 4) | b) + out.append(current) + + if args.ucl: + compressed = [] + for block in out: + p = subprocess.Popen(["ucl",], stdin=subprocess.PIPE, stdout=subprocess.PIPE) + output, err = p.communicate(bytearray(block)) + compressed.append([ord(b) for b in output]) + out = compressed + + if args.bin: + sys.stdout.write(bytearray(out)) + return + + print("#define WMAPS %d" % (mw // args.rw)) + + if args.ucl: + data_out = "" + for i, block in enumerate(out): + data_out_part = "" + for part in range(0, len(block), args.rw // 2): + if data_out_part: + data_out_part += ",\n" + data_out_part += ', '.join(["0x%02x" % b for b in block[part: part + args.rw // 2]]) + data_out += "const unsigned char %s_%d[%d] = {\n" % (args.id, i, len(block)) + data_out += data_out_part + "\n};\n" + + data_out += "const unsigned char *%s[%d] = { " % (args.id, len(out)) + data_out += ', '.join(["%s_%d" % (args.id, i) for i in range(len(out))]) + data_out += " };\n" + print(data_out) + + else: + data_out = "" + for block in out: + if data_out: + data_out += ",\n" + data_out += "{" + for part in range(0, len(block), args.rw // 2): + if data_out and data_out[-1] != "{": + data_out += ",\n" + data_out += ', '.join(["0x%02x" % b for b in block[part: part + args.rw // 2]]) + data_out += "}\n" + + print("const unsigned char %s[%d][%d] = {\n%s\n};\n" % (args.id, + len(out), args.rh * args.rw / 2, data_out)) + + enemies = 0 + entities_layer = find_name(data["layers"], "Entities") + if len(entities_layer): + map_ents = defaultdict(list) + ent_tileset = find_name(data["tilesets"], "Entities") + firstgid = ent_tileset.get("firstgid") + for obj in entities_layer["objects"]: + m = ((obj["x"] // tilewidth) // args.rw) \ + + (((obj["y"] // tileheight) // args.rh) * (mw // args.rw)) + x = obj["x"] % (args.rw * tilewidth) + y = obj["y"] % (args.rh * tileheight) - ent_tileset["tileheight"] + t = int(ent_tileset["tileproperties"][str(obj["gid"] - firstgid)]["id"]) + # enemies start at id 10 + if t > 9: + enemies += 1 + map_ents[m].extend([t, x, y]) + if "teleport" in obj.get("properties", {}): + tele = json.loads(obj["properties"]["teleport"]) + tm = ((tele[0] // tilewidth) // args.rw) \ + + (((tele[1] // tileheight) // args.rh) * (mw // args.rw)) + map_ents[m].extend([tm, tele[0] % (tilewidth * args.rw), tele[1] % (tileheight * args.rh) - ent_tileset["tileheight"]]) + + for m, ents in map_ents.items(): + data_out = ", ".join(["0x%02x" % e for e in ents]) + ", 0xff" + print("const unsigned char %s_e%d[%d] = { %s };" % (args.id, m, len(ents) + 1, data_out)) + + map_map = [] + for i in range(len(out)): + if i in map_ents: + map_map.append("%s_e%d" % (args.id, i)) + else: + map_map.append("(unsigned char *)0") + + print("const unsigned char *%s_ents[%d] = { %s };\n" % (args.id, + len(out), ", ".join(map_map))) + + print("const unsigned char %s_enemies = %s;" % (args.id, enemies)) + +if __name__ == "__main__": + main() + diff --git a/tools/ucl.c b/tools/ucl.c new file mode 100644 index 0000000..e61e0e0 --- /dev/null +++ b/tools/ucl.c @@ -0,0 +1,94 @@ +/* +ucl compression tool +Copyright (C) 2015 by Juan J. Martinez - usebox.net + +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. +*/ + +#include +#include + +#include + +#define MAX_MEM 65536 + +ucl_byte buffer[MAX_MEM]; + +int +main() +{ + ucl_uint in_len = 0; + ucl_uint out_len; + ucl_byte *in; + ucl_byte *out; + + if (ucl_init() != UCL_E_OK) + { + fprintf(stderr, "ucl: failed to init UCL\n"); + return 1; + } + + while(!feof(stdin)) + { + buffer[in_len++] = getc(stdin); + if (in_len > MAX_MEM) + { + fprintf(stderr, "input too large (limit %i)\n", MAX_MEM); + return 1; + } + } + in_len--; + + out_len = in_len + in_len / 8 + 256; + + in = ucl_malloc(in_len + 8192); + out = ucl_malloc(out_len + 8192); + if (!in || !out) + { + fprintf(stderr, "ucl: out of memory\n"); + return 1; + } + + memcpy(in, buffer, in_len); + + if (ucl_nrv2b_99_compress(in, in_len, out, &out_len, NULL, 10, NULL, NULL) != UCL_E_OK) + { + fprintf(stderr, "ucl: compress error\n"); + return 1; + } + + if (out_len >= in_len) + { + fprintf(stderr, "ucl: content can't be compressed\n"); + return 1; + } + + fwrite(out, 1, out_len, stdout); + fclose(stdout); + + ucl_free(out); + ucl_free(in); + + fprintf(stderr, "ucl: %i bytes compressed into %i bytes\n", in_len, out_len); + + return 0; +} + + + diff --git a/turboload.s b/turboload.s new file mode 100644 index 0000000..b72adea --- /dev/null +++ b/turboload.s @@ -0,0 +1,249 @@ +;; Modified Topo soft loader +;; +;; Multi-colour bars in the border, aka "Spanish" style Spectrum variant loader. +;; +;; This loader uses standard Spectrum ROM timings. In fact it is essentially a CPC version of the +;; Spectrum ROM loader itself. +;; +;; +;; Loader form on cassette: +;; Pilot tone (min 256 pulses) +;; Sync pulse +;; 1 byte sync byte (on spectrum 0 for header and &ff for data) +;; n bytes of data (defined by DE register) +;; 1 byte parity checksum +;; +;; Original had the following bugs: +;; 1. bit 7 of R register had to be 1, otherwise it could change ram/rom configuration while loading +;; 2. flags were not returned, so you didn't know if the data was read incorrectly or not +;; +;; It also had extra code that was unnecessary: +;; 1. turning cassette motor on/off was complex, when in previous instructions they had turned it on anyway. +;; 2. code for changing border colour presumably on a read error. but didn't seem to be used. +;; +;; +;; Entry conditions: +;; +;; IX = start +;; DE = length (D must not be &ff) +;; A = sync byte expected +;; +;; Interrupts must be disabled +;; +;; Exit Conditions: +;; Alternative register set is corrupted. +;; +;; carry clear - load ok +;; carry set, zero set - time up +;; carry set, zero reset - if esc pressed +;; +;; Use 2CDT to write Spectrum ROM blocks to a CDT. Note that at this time it will only write a sync byte of &ff. + +_turboload: + +inc d ;; reset the zero flag (D cannot hold &ff) +ex af,af' ;; A register holds sync byte. +dec d ;; restore D +exx +;; we need B' to be so we can write to gate-array i/o port for colour change when loading + +ld bc,#0x7f00+#0x10 ;; Gate-Array + border +out (c),c ;; select pen index to change while loading (&10 is border) +ld c,#0x54 ;; set to black +out (c),c +exx + +ld bc,#0xf40e ;; select AY register 14 (for reading keyboard) +out (c),c + +ld bc,#0xf600+#0xc0+#0x10 ;; "AY write register" and enable tape motor +out (c),c + +ld c,#0x10 ;; "AY inactive" and enable tape motor (register is latched into AY) +out (c),c + +ld bc,#0xf792 ;; set PPI port A to read (so we can read keyboard data) +out (c),c ;; this will also write 0 to port C and port A on CPC. + +ld bc,#0xf600+#0x40+#0x10+#0x8 ;; tape motor enable, "AY read register", select keyboard row 8 + ;; (keys on this row: z, caps lock, a, tab, q, esc, 2, 1) + ;; we are only interested in ESC +out (c),c + +;; make an initial read of cassette input +ld a,#0xf5 ;; PPI port B +in a,(#0) ;; read port (tape read etc) +and #0x80 ;; isolate tape read data + +ld c,a +cp a ;; set the zero flag +l8107: +ret nz ;; returns if esc key is pressed (was RET NZ) +l8108: +call l817b +jr nc,l8107 + +;; the wait is meant to be almost one second +ld hl,#0x415 +l8110: +djnz l8110 +dec hl +ld a,h +or l +jr nz,l8110 +;; continue if only two edges are found within this allowed time period +call l8177 +jr nc,l8107 + +;; only accept leader signal +l811c: +ld b,#0x9c +call l8177 +jr nc,l8107 +ld a,#0xb9 +cp b +jr nc,l8108 +inc h +jr nz,l811c + +;; on/off parts of sync pulse +l812b: +ld b,#0xc9 +call l817b +jr nc,l8107 +ld a,b +cp #0xd1 +jr nc,l812b +l8137: +call l817b +ret nc + +ld h,#0 ;; parity matching byte (checksum) +ld b,#0xb0 ;; timing constant for flag byte and data +jr l815d + +l8145: +ex af,af' ;; fetch the flags +jr nz,l814d ;; jump if we are handling first byte +;; L = data byte read from cassette +;; store to RAM +ld 0(ix),l +jr l8157 + +l814d: +rr c ;; keep carry in safe place + ;; NOTE: Bit 7 is cassette read previous state + ;; We need to do a right shift so that cassette read moves into bit 6, + ;; our stored carry then goes into bit 7 +xor l ;; check sync byte is as we expect +ret nz + +ld a,c ;; restore carry flag now +rla ;; bit 7 goes into carry restoring it, bit 6 goes back to bit 7 to restore tape input value +ld c,a +inc de ;; increase counter to compensate for it's decrease +jr l8159 + +l8157: +inc ix ;; increase destination +l8159: +dec de ;; decrease counter +ex af,af' ;; save the flags + +ld b,#0xb2 ;; timing constant +l815d: +ld l,#1 ;; marker bit (defines number of bits to read, and finally becomes value read) +l815f: +call l8177 +ret nc + +ld a,#0xc3 ;; compare the length against approx 2,400T states, resetting the carry flag for a '0' and setting it for a '1' +cp b +rl l ;; include the new bit in the register +ld b,#0xb0 ;; set timing constant for next bit +jr nc,l815f + +;; L = data byte read +;; combine with checksum +ld a,h +xor l +ld h,a + +;; DE = count +ld a,d +or e +jr nz,l8145 + +exx +ld c,#0x54 ;; make border black +out (c),c +exx + +ld bc,#0xf782 ;; set PPI port A for output +out (c),c +ld bc,#0xf600 ;; tape motor off, "AY inactive" +out (c),c + +;; H = checksum byte +;; H = 0 means checksum ok +ld a,h +cp #1 +;; return with carry flag set if the result is good +;; carry clear otherwise +ret + + +;;------------------------------------------------------------ +l8177: +call l817b ;; in effect call ld-edge-1 twice returning in between if there is an error +ret nc + +;; wait 358T states before entering sampling loop +l817b: +ld a,#0x16 ;; [2] +l817d: +dec a ;; [1] +jr nz,l817d ;; ([3]+[1])*&15+[2] + +and a +l8181: +inc b ;; count each pass +ret z ;; return carry reset and zero set if time up. + +;; read keyboard +ld a,#0xf4 ;; PPI port A +in a,(#0) ;; read port and read keyboard through AY register 14 +and #0x04 ;; isolate state of bit 2 (ESC key) + ;; bit will be 0 if key is pressed +xor #0x04 ;; has key been pressed? +ret nz ;; quit (carry reset, zero reset) + +ld a,#0xf5 ;; PPI port B +in a,(#0) ;; read port (tape read etc) +xor c +and #0x80 ;; isolate tape read +jr z,l8181 +ld a,c ;; effectively toggle bit 7 of C +cpl ;; which is the tape read state we want to see next +ld c,a + +exx ;; swap to alternative register set so that we can change colour +;; this sets colour and gives us the multi colour border +;ld a,r ;; get R register +;and #0x1f ;; ensure it is in range of colour value + +nop +nop +nop +and #4 + +or #0x40 ;; bit 7 = 0, bit 6 = 1 +out (c),a ;; write colour value +nop ;; this is to ensure the number of cycles is the same + ;; compared to the replaced instructions + ;; (timings from toposoft loader) +nop +exx +scf +ret + -- cgit v1.2.3