aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuan J. Martinez <jjm@usebox.net>2021-05-03 08:21:10 +0100
committerJuan J. Martinez <jjm@usebox.net>2021-05-03 10:00:00 +0100
commitc3b0fa04a663fe233765b83d3be41a42aa08c25d (patch)
tree0befda349001ef6ce306b39378f9c70ad917363e
downloadreturn-of-traxtor-cpc-c3b0fa04a663fe233765b83d3be41a42aa08c25d.tar.gz
return-of-traxtor-cpc-c3b0fa04a663fe233765b83d3be41a42aa08c25d.zip
Initial import for public releaseHEADmain
-rw-r--r--.gitignore18
-rw-r--r--Makefile131
-rw-r--r--README.md46
-rw-r--r--cpcfirm.inc227
-rw-r--r--crt0.s55
-rw-r--r--font.gifbin0 -> 289 bytes
-rw-r--r--gpl-3.0.txt674
-rw-r--r--int.h100
-rw-r--r--lib/Makefile20
-rw-r--r--lib/cpcrslib/GphStrStd.s412
-rw-r--r--lib/cpcrslib/LICENSE20
-rw-r--r--lib/cpcrslib/Makefile23
-rw-r--r--lib/cpcrslib/Sprites.s37
-rw-r--r--lib/cpcrslib/TileMap.h304
-rw-r--r--lib/cpcrslib/Wyz.s1403
-rw-r--r--lib/cpcrslib/cpc_ClrScr.s11
-rw-r--r--lib/cpcrslib/cpc_CollSp.s126
-rw-r--r--lib/cpcrslib/cpc_DisableEnableFirmware.s28
-rw-r--r--lib/cpcrslib/cpc_GetScrAddress.s65
-rw-r--r--lib/cpcrslib/cpc_GetSp.s49
-rw-r--r--lib/cpcrslib/cpc_GphStr.s700
-rw-r--r--lib/cpcrslib/cpc_Keyboard.s348
-rw-r--r--lib/cpcrslib/cpc_PrintStr.s27
-rw-r--r--lib/cpcrslib/cpc_PutMaskSp.s79
-rw-r--r--lib/cpcrslib/cpc_PutMaskSp2x8.s45
-rw-r--r--lib/cpcrslib/cpc_PutMaskSp4x16.s56
-rw-r--r--lib/cpcrslib/cpc_PutSp.s54
-rw-r--r--lib/cpcrslib/cpc_PutSp2x14.s50
-rw-r--r--lib/cpcrslib/cpc_PutSpTr.s75
-rw-r--r--lib/cpcrslib/cpc_PutSpXOR.s79
-rw-r--r--lib/cpcrslib/cpc_PutSprite.s108
-rw-r--r--lib/cpcrslib/cpc_RLI.s39
-rw-r--r--lib/cpcrslib/cpc_RRI.s39
-rw-r--r--lib/cpcrslib/cpc_Random.s34
-rw-r--r--lib/cpcrslib/cpc_SetBorder.s10
-rw-r--r--lib/cpcrslib/cpc_SetColour.s16
-rw-r--r--lib/cpcrslib/cpc_SetInk.s12
-rw-r--r--lib/cpcrslib/cpc_SetMode.s13
-rw-r--r--lib/cpcrslib/cpc_SetModo.s9
-rw-r--r--lib/cpcrslib/cpc_TileMap.s1332
-rw-r--r--lib/cpcrslib/cpc_UnExoOpt.s183
-rw-r--r--lib/cpcrslib/cpc_Uncrunch.s308
-rw-r--r--lib/cpcrslib/cpcrslib.h116
-rw-r--r--lib/cpcrslib/cpcwyzlib.h18
-rw-r--r--lib/cpcrslib/make.bat19
-rw-r--r--lib/ucl.h5
-rw-r--r--lib/ucl.s360
-rw-r--r--loader.s157
-rw-r--r--loading.pngbin0 -> 2336 bytes
-rw-r--r--main.c1794
-rw-r--r--menu.pngbin0 -> 595 bytes
-rw-r--r--mock.pngbin0 -> 2413 bytes
-rw-r--r--music/board.musbin0 -> 97 bytes
-rw-r--r--music/gameover.musbin0 -> 121 bytes
-rw-r--r--music/intro.musbin0 -> 77 bytes
-rw-r--r--music/return.musbin0 -> 1019 bytes
-rw-r--r--music/theplayer.musbin0 -> 1215 bytes
-rw-r--r--play.pngbin0 -> 787 bytes
-rw-r--r--ship.pngbin0 -> 303 bytes
-rw-r--r--sound.c40
-rw-r--r--sound.h36
-rw-r--r--splib.c325
-rw-r--r--splib.h64
-rw-r--r--tiles-work.pngbin0 -> 968 bytes
-rw-r--r--tiles.pngbin0 -> 802 bytes
-rw-r--r--tiles_alt.pngbin0 -> 562 bytes
-rw-r--r--tools/2CDT/2cdt.cbp43
-rw-r--r--tools/2CDT/2cdt.depend22
-rw-r--r--tools/2CDT/2cdt.layout7
-rw-r--r--tools/2CDT/COPYING340
-rw-r--r--tools/2CDT/Makefile24
-rw-r--r--tools/2CDT/Makefile.win33
-rw-r--r--tools/2CDT/file_id.diz16
-rw-r--r--tools/2CDT/readme.txt135
-rw-r--r--tools/2CDT/src/2cdt.c1290
-rw-r--r--tools/2CDT/src/defs.h36
-rw-r--r--tools/2CDT/src/tzxfile.c445
-rw-r--r--tools/2CDT/src/tzxfile.h79
-rw-r--r--tools/Makefile38
-rw-r--r--tools/README.ucl7
-rwxr-xr-xtools/bin2h.py34
-rwxr-xr-xtools/chksize42
-rwxr-xr-xtools/dump-pal.py95
-rw-r--r--tools/encrypt.py25
-rw-r--r--tools/gfx2crtc/AUTHORS5
-rw-r--r--tools/gfx2crtc/LICENCE512
-rw-r--r--tools/gfx2crtc/LICENSE506
-rw-r--r--tools/gfx2crtc/README36
-rw-r--r--tools/gfx2crtc/TODO9
-rw-r--r--tools/gfx2crtc/libraw2crtc.c186
-rw-r--r--tools/gfx2crtc/libraw2crtc.h12
-rw-r--r--tools/gfx2crtc/makefile29
-rw-r--r--tools/gfx2crtc/png2crtc.c204
-rw-r--r--tools/gfx2crtc/raw2crtc.c86
-rwxr-xr-xtools/hex2bin-2.0/Makefile42
-rw-r--r--tools/hex2bin-2.0/bin/.deleteme0
-rwxr-xr-xtools/hex2bin-2.0/bin/hex2binbin0 -> 33200 bytes
-rwxr-xr-xtools/hex2bin-2.0/bin/mot2binbin0 -> 33200 bytes
-rw-r--r--tools/hex2bin-2.0/doc/CRC list.txt542
-rw-r--r--tools/hex2bin-2.0/doc/ChangeLog_hex2bin57
-rw-r--r--tools/hex2bin-2.0/doc/ChangeLog_mot2bin49
-rw-r--r--tools/hex2bin-2.0/doc/README225
-rw-r--r--tools/hex2bin-2.0/doc/S-record.txt361
-rw-r--r--tools/hex2bin-2.0/doc/formats.txt72
-rw-r--r--tools/hex2bin-2.0/doc/intelhex.spc409
-rw-r--r--tools/hex2bin-2.0/doc/srec.txt447
-rw-r--r--tools/hex2bin-2.0/src/binary.c196
-rw-r--r--tools/hex2bin-2.0/src/binary.h36
-rw-r--r--tools/hex2bin-2.0/src/common.c527
-rw-r--r--tools/hex2bin-2.0/src/common.h116
-rw-r--r--tools/hex2bin-2.0/src/hex2bin.1294
-rw-r--r--tools/hex2bin-2.0/src/hex2bin.c587
-rw-r--r--tools/hex2bin-2.0/src/hex2bin.pod161
-rw-r--r--tools/hex2bin-2.0/src/libcrc.c204
-rw-r--r--tools/hex2bin-2.0/src/libcrc.h44
-rw-r--r--tools/hex2bin-2.0/src/mot2bin.c518
-rw-r--r--tools/iDSK/.gitignore7
-rw-r--r--tools/iDSK/AUTHORS3
-rw-r--r--tools/iDSK/CMakeLists.txt14
-rw-r--r--tools/iDSK/COPYING1
-rw-r--r--tools/iDSK/src/Basic.cpp350
-rw-r--r--tools/iDSK/src/Basic.h8
-rw-r--r--tools/iDSK/src/BitmapCPC.cpp264
-rw-r--r--tools/iDSK/src/BitmapCPC.h46
-rw-r--r--tools/iDSK/src/Dams.cpp184
-rw-r--r--tools/iDSK/src/Dams.h8
-rw-r--r--tools/iDSK/src/Desass.cpp532
-rw-r--r--tools/iDSK/src/Desass.h8
-rw-r--r--tools/iDSK/src/GestDsk.cpp1183
-rw-r--r--tools/iDSK/src/GestDsk.h168
-rw-r--r--tools/iDSK/src/Main.cpp284
-rw-r--r--tools/iDSK/src/Main.h19
-rw-r--r--tools/iDSK/src/MyType.h19
-rw-r--r--tools/iDSK/src/Outils.cpp165
-rw-r--r--tools/iDSK/src/Outils.h19
-rw-r--r--tools/iDSK/src/ViewFile.cpp36
-rw-r--r--tools/iDSK/src/ViewFile.h13
-rw-r--r--tools/iDSK/src/endianPPC.cpp20
-rw-r--r--tools/iDSK/src/endianPPC.h22
-rw-r--r--tools/iDSK/src/getopt_pp.cpp307
-rw-r--r--tools/iDSK/src/getopt_pp.h745
-rwxr-xr-xtools/img2f.py54
-rwxr-xr-xtools/img2sprite.py115
-rwxr-xr-xtools/map.py162
-rw-r--r--tools/ucl.c94
-rw-r--r--turboload.s249
146 files changed, 24581 insertions, 0 deletions
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
--- /dev/null
+++ b/font.gif
Binary files 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. <https://fsf.org/>
+ 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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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 <https://www.gnu.org/licenses/>.
+
+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:
+
+ <program> Copyright (C) <year> <name of author>
+ 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
+<https://www.gnu.org/licenses/>.
+
+ 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
+<https://www.gnu.org/licenses/why-not-lgpl.html>.
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 <jjm@usebox.net>
+
+ 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 <https://www.gnu.org/licenses/>.
+ */
+#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 @@
+; ******************************************************
+; ** Librería de rutinas SDCC para Amstrad CPC **
+; ** Raúl Simarro (Artaburu) - 2009, 2012 **
+; ******************************************************
+
+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
+
+
+
+
+.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::
+;preparación datos impresión. 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 impresión. No se interrumpe
+ ;la impresión 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 número 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 <artaburu@hotmail.com>
+
+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 @@
+; ******************************************************
+; ** Librería de rutinas SDCC para Amstrad CPC **
+; ** Raúl 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.
+; Selección color transparente. Escribir las 2 máscaras 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 tamaño del buffer es ancho_pantalla_bytes*alto_pantalla_bytes
+
+_TileMapConf:
+;------------------------------------------------------------------------------------
+;Con la definición del mapeado hay que tener en cuenta que las coordenadas son:
+;ANCHO=64 bytes (128 pixels en modo 0)
+;ALTO=128 pixels
+;el máximo que entra en el CPC es 20 líneas
+;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 línea (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 @@
+; ******************************************************
+; ** Librería de rutinas para Amstrad CPC **
+; ** Raúl 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,... sólo hay que inicializar esos datos
+; en la librería
+ 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 parámetros: 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 @@
+; ******************************************************
+; ** Librería de rutinas SDCC para Amstrad CPC **
+; ** Raúl Simarro (Artaburu) - 2009, 2012 **
+; ******************************************************
+
+
+
+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
+
+
+
+
+;*************************************
+; GRAPHIC TEXT
+;*************************************
+
+.globl _cpc_PrintGphStr2X
+
+_cpc_PrintGphStr2X::
+;preparación datos impresión. 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::
+;preparación datos impresión. 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::
+;preparación datos impresión. 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::
+;preparación datos impresión. 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 impresión. No se interrumpe
+ ;la impresión 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 añaden 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 número 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 sería
+ 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 ACTÚA 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 ;SÓLO SE DARÍA 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::
+;preparación datos impresión. 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::
+;preparación datos impresión. 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::
+;preparación datos impresión. 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::
+;preparación datos impresión. 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 impresión. No se interrumpe
+ ;la impresión 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 número 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 sería
+ 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 ACTÚA 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 ;sólo se daría 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 dirección origen de los datos de la letra
+ ;LD DE,letra ;el destino es la posición de decodificación 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 máximo 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 dirección 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 máximo 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 número 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 posición 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 tamaño 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 @@
+; ******************************************************
+; ** Librería de rutinas SDCC para Amstrad CPC **
+; ** Raúl 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 línea del teclado correspondiente
+ DEC HL ; pero sólo 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 posición leída
+ 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 máximo 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 después 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 después 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 LÍNEA BUSCADA DEL KEYMAP
+ LD C,A
+ LD B,#0
+ ADD HL,BC
+ LD A,(HL)
+ EX DE,HL
+ DEC HL ; PERO SÓLO 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 básicas 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 línea.
+tabla_teclas:
+tecla_0_x: .DW #0xffff ; bit 0, línea 2
+tecla_1_x: .DW #0xffff ; bit 1, línea 1
+tecla_2_x: .DW #0xffff ; bit 0, línea 1
+tecla_3_x: .DW #0xffff ; bit 0, línea 4
+tecla_4_x: .DW #0xffff ; bit 0, línea 2
+tecla_5_x: .DW #0xffff ; bit 1, línea 1
+tecla_6_x: .DW #0xffff ; bit 0, línea 1
+tecla_7_x: .DW #0xffff ; bit 0, línea 4
+tecla_8_x: .DW #0xffff ; bit 0, línea 4
+tecla_9_x: .DW #0xffff ; bit 0, línea 4
+tecla_10_x: .DW #0xffff ; bit 0, línea 4
+tecla_11_x: .DW #0xffff ; bit 0, línea 4
+tecla_12_x: .DW #0xffff ; bit 0, línea 4
+tecla_13_x: .DW #0xffff ; bit 0, línea 4
+tecla_14_x: .DW #0xffff ; bit 0, línea 4
+tecla_15_x: .DW #0xffff ; bit 0, línea 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
+
+
+
+
+; ******************************************************
+; ** Librería de rutinas para Amstrad CPC **
+; ** Raúl 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 número 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
+
+ ; Posición 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 dirección 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 posición
+ ;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 número 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 línea
+
+ 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: ; código 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
+
+
+
+;según 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 revés)
+ 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 añade
+ 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 MÁS 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 posición 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 cálculo
+ 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 posición 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: Posición 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::
+
+;según 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 posición 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 línea
+ add HL,BC
+ jp loop_alto_map_sbuffer2
+
+
+.globl _cpc_PutMaskSpTileMap2b
+
+_cpc_PutMaskSpTileMap2b::
+;según 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 posición 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 línea
+ add HL,BC
+ jp loop_alto_map_sbuffer3
+
+
+
+
+
+
+
+
+.globl _cpc_PutMaskInkSpTileMap2b
+
+_cpc_PutMaskInkSpTileMap2b::
+;según 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 posición 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 línea
+ 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 parámetros? ¿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 posición 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 @@
+; ******************************************************
+; ** Librería de rutinas SDCC para Amstrad CPC **
+; ** Raúl 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 @@
+; ******************************************************
+; ** Librería de rutinas SDCC para Amstrad CPC **
+; ** Raúl 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 INTERRUPCIÓN 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
+; <adam@foxbox.org> <adam@gimp.org> - 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:
+; <http://www.foxbox.org/adam/code/uclz80/>
+;
+;
+; 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
--- /dev/null
+++ b/loading.png
Binary files 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 <jjm@usebox.net>
+
+ 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 <https://www.gnu.org/licenses/>.
+ */
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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
--- /dev/null
+++ b/menu.png
Binary files differ
diff --git a/mock.png b/mock.png
new file mode 100644
index 0000000..d460bec
--- /dev/null
+++ b/mock.png
Binary files differ
diff --git a/music/board.mus b/music/board.mus
new file mode 100644
index 0000000..b8b9039
--- /dev/null
+++ b/music/board.mus
Binary files differ
diff --git a/music/gameover.mus b/music/gameover.mus
new file mode 100644
index 0000000..d6d20ab
--- /dev/null
+++ b/music/gameover.mus
Binary files differ
diff --git a/music/intro.mus b/music/intro.mus
new file mode 100644
index 0000000..0c66482
--- /dev/null
+++ b/music/intro.mus
Binary files differ
diff --git a/music/return.mus b/music/return.mus
new file mode 100644
index 0000000..0e4caac
--- /dev/null
+++ b/music/return.mus
Binary files differ
diff --git a/music/theplayer.mus b/music/theplayer.mus
new file mode 100644
index 0000000..caf2703
--- /dev/null
+++ b/music/theplayer.mus
Binary files differ
diff --git a/play.png b/play.png
new file mode 100644
index 0000000..afb7531
--- /dev/null
+++ b/play.png
Binary files differ
diff --git a/ship.png b/ship.png
new file mode 100644
index 0000000..728d934
--- /dev/null
+++ b/ship.png
Binary files 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 <jjm@usebox.net>
+
+ 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 <https://www.gnu.org/licenses/>.
+ */
+#include <stdint.h>
+
+#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 <jjm@usebox.net>
+
+ 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 <https://www.gnu.org/licenses/>.
+ */
+#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 <jjm@usebox.net>
+
+ 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 <https://www.gnu.org/licenses/>.
+ */
+#include <stdlib.h>
+
+#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 <jjm@usebox.net>
+
+ 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 <https://www.gnu.org/licenses/>.
+ */
+#ifndef _SPLIB_H
+#define _SPLIB_H
+
+#include <stdint.h>
+
+// 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
--- /dev/null
+++ b/tiles-work.png
Binary files differ
diff --git a/tiles.png b/tiles.png
new file mode 100644
index 0000000..eb7ca34
--- /dev/null
+++ b/tiles.png
Binary files differ
diff --git a/tiles_alt.png b/tiles_alt.png
new file mode 100644
index 0000000..e4e93f0
--- /dev/null
+++ b/tiles_alt.png
Binary files 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 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<CodeBlocks_project_file>
+ <FileVersion major="1" minor="4" />
+ <Project>
+ <Option title="2cdt" />
+ <Option makefile="makefile" />
+ <Option pch_mode="0" />
+ <Option compiler="gcc" />
+ <Build>
+ <Target title="default">
+ <Option output="C:\2cdt\2cdt.exe" />
+ <Option type="1" />
+ <Option compiler="gcc" />
+ <Option parameters="-m 2 -r snake c:\blocks.bin c:\tester.cdt" />
+ <Option includeInTargetAll="1" />
+ <Option projectResourceIncludeDirsRelation="1" />
+ </Target>
+ </Build>
+ <Compiler>
+ <Add option="-g" />
+ </Compiler>
+ <Unit filename="src\2cdt.c">
+ <Option compilerVar="CC" />
+ <Option target="default" />
+ </Unit>
+ <Unit filename="src\defs.h">
+ <Option compilerVar="CC" />
+ <Option compile="0" />
+ <Option link="0" />
+ <Option target="default" />
+ </Unit>
+ <Unit filename="src\tzxfile.c">
+ <Option compilerVar="CC" />
+ <Option target="default" />
+ </Unit>
+ <Unit filename="src\tzxfile.h">
+ <Option compilerVar="CC" />
+ <Option compile="0" />
+ <Option link="0" />
+ <Option target="default" />
+ </Unit>
+ </Project>
+</CodeBlocks_project_file> \ 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
+ <stdio.h>
+ <stdlib.h>
+ <memory.h>
+ "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
+ <stdio.h>
+ <stdlib.h>
+ <string.h>
+ <sys/io.h>
+ <io.h>
+ "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 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<CodeBlocks_layout_file>
+ <ActiveTarget name="All" />
+ <File name="src\2cdt.c" open="1" top="1" tabpos="1">
+ <Cursor position="26859" topLine="1012" />
+ </File>
+</CodeBlocks_layout_file>
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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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.
+
+ <signature of Ty Coon>, 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] <source file> <output CDT filename>
+
+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 <speed write>
+ - 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 <baud rate>
+ - Specify Baud Rate.
+
+ Allows you to specify faster or slower loading.
+
+ -t <method>
+ - Method to write data into TZX (for Amstrad blocks)
+ 0 = Pure Data Block
+ 1 = Turbo Loading Data Block (default)
+
+ -m <method>
+ - 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 <tape filename>
+ - 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 <address>
+ Define execution address (where file doesn't have header), or
+ override execution address (where file has a header)
+
+ -L <address>
+ Define load address (where file doesn't have header), or
+ override load address (where file has a header)
+
+ -T <address>
+ Define type (where file doesn't have header), or
+ override type address (where file has a header)
+ 0 = BASIC, 2 = BINARY
+
+ -p <number>
+ 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef UNIX
+#include <sys/io.h>
+#else
+#include <io.h>
+#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<DataSize; i++)
+ {
+ char ch = *pData;
+ ++pData;
+ CheckSum^=ch;
+ *pBlockData = ch;
+ ++pBlockData;
+ }
+ *pBlockData = CheckSum&0x0ff;
+ }
+ }
+}
+
+
+#define CPC_DATA_CHUNK_SIZE 256
+#define CPC_DATA_BLOCK_SIZE 2048
+
+/* write a block of data to a file */
+void CPC_WriteTurboLoadingDataBlock(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;
+
+
+
+ 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<NumChunks; i++)
+ {
+ /* copy data into block */
+ if (DataSizeRemaining<CPC_DATA_CHUNK_SIZE)
+ {
+ /* less than CPC_DATA_CHUNK_SIZE */
+ /* copy data, and fill rest with zeros */
+
+ /* copy less than 256 bytes */
+ memcpy(pBlockPtr, pDataPtr, DataSizeRemaining);
+ /* fill reset of chunk with zero's */
+ memset(pBlockPtr + DataSizeRemaining, 0, CPC_DATA_CHUNK_SIZE-DataSizeRemaining);
+ /* update source pointer */
+ pDataPtr+=DataSizeRemaining;
+ /* update size remaining - nothing */
+ DataSizeRemaining = 0;
+ }
+ else
+ {
+ /* greater or equal to CPC_DATA_CHUNK_SIZE */
+ /* copy CPC_DATA_CHUNK_SIZE max */
+ memcpy(pBlockPtr, pDataPtr, CPC_DATA_CHUNK_SIZE);
+ /* update source pointer */
+ pDataPtr += CPC_DATA_CHUNK_SIZE;
+ /* update size remaining */
+ DataSizeRemaining-=CPC_DATA_CHUNK_SIZE;
+ }
+
+ /* reset CRC */
+ CRC = 0x0ffff;
+
+ /* calculate CRC for block */
+ for (j=0; j<CPC_DATA_CHUNK_SIZE; j++)
+ {
+ char ch;
+
+ ch = pBlockPtr[0];
+ pBlockPtr++;
+ CRC = CRCupdate(CRC, ch);
+ }
+
+ /* store CRC inverted */
+ pBlockPtr[0] = (CRC>>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<CPC_PILOT_TONE_NUM_WAVES; i++)
+ {
+ BitStream_WriteBit(1);
+ }
+
+ BitStream_WriteBit(0);
+
+
+ BitStream_WriteByte(SyncPattern);
+
+ /* write each chunk in turn and calculate CRC */
+ for (i=0; i<NumChunks; i++)
+ {
+ int BlockSizeToWrite;
+
+ /* copy data into block */
+ if (DataSizeRemaining<CPC_DATA_CHUNK_SIZE)
+ {
+ BlockSizeToWrite = DataSizeRemaining;
+ }
+ else
+ {
+ BlockSizeToWrite = CPC_DATA_CHUNK_SIZE;
+ }
+
+ CRC = 0x0ffff;
+
+ for (j=0; j<BlockSizeToWrite; j++)
+ {
+ char ch;
+
+ /* get byte */
+ ch = pDataPtr[0];
+ pDataPtr++;
+ /* update CRC */
+ CRC = CRCupdate(CRC, ch);
+ /* write byte to stream */
+ BitStream_WriteByte(ch);
+ }
+
+ if (BlockSizeToWrite!=CPC_DATA_CHUNK_SIZE)
+ {
+ /* write padding zero's */
+ for (j=0; j<(CPC_DATA_CHUNK_SIZE-BlockSizeToWrite); j++)
+ {
+ char ch;
+
+ ch = 0;
+ /* update CRC */
+ CRC = CRCupdate(CRC, ch);
+ /* write byte to stream */
+ BitStream_WriteByte(ch);
+ }
+ }
+
+ DataSizeRemaining-=BlockSizeToWrite;
+
+ CRC = CRC^0x0ffff;
+
+ BitStream_WriteByte((CRC>>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] <input filename> <.cdt image>\r\n\r\n", UTILITY_NAME);
+ printf("-n - Blank CDT file before use\n");
+ printf("-b <number> - 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 <method> - TZX Block Write Method.\n");
+ printf(" 0 = Pure Data, 1 = Turbo Loading (default)\n");
+ printf("-m <method> - 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 <number> = Define or override execution address (default is &1000 if no header)\r\n");
+ printf("-L <number> = Define or override load address (default is &1000 if no header)\r\n");
+ printf("-F <number> = Define or override file type (0=BASIC, 2=Binary (default if no header)) etc. Applies to Data method 0\r\n");
+ printf("-p <number> = 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 <tape filename>\n");
+ printf(" - Add <input filename> as <tape filename> 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 <number> - 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 <method> - TZX Block Write Method.\n");
+ printf(" 0 = Pure Data, 1 = Turbo Loading (default)\n");
+ printf("-m <method> - 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 <number> = Define or override execution address (default is &1000 if no header)\r\n");
+ printf("-L <number> = Define or override load address (default is &1000 if no header)\r\n");
+ printf("-F <number> = Define or override file type (0=BASIC, 2=Binary (default if no header)) etc. Applies to Data method 0\r\n");
+ printf("-p <number> = 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 <tape filename>\n");
+ printf(" - Add <input filename> as <tape filename> 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<nLength; i++)
+ {
+ TapeHeader[i] = toupper(pTapeFilename[i]);
+ }
+ }
+ TapeHeader[CPC_TAPE_HEADER_DATA_LOGICAL_LENGTH_LOW] = (FileLengthRemaining & 0x0ff);
+ TapeHeader[CPC_TAPE_HEADER_DATA_LOGICAL_LENGTH_HIGH] = (FileLengthRemaining>>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 <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+/* 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 <jjm@usebox.net>",
+ )
+
+ 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 <jjm@usebox.net>",
+ )
+
+ 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) <cloudstrife@cpcscene.com>
+
+Contributors:
+PulkoMandy/Shinra (Adrien Destugues) <pulkomandy@gmail.com>
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 préside à
+sa rédaction:
+
+ * d'une part, le respect des principes de diffusion des logiciels
+ libres: accès au code source, droits étendus conférés aux
+ utilisateurs,
+ * d'autre part, la désignation d'un droit applicable, le droit
+ français, auquel elle est conforme, tant au regard du droit de la
+ responsabilité civile que du droit de la propriété 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 à caractère scientifique, technique et industriel, dont le
+siège est situé 25 rue Leblanc, immeuble Le Ponant D, 75015 Paris.
+
+Centre National de la Recherche Scientifique - CNRS, établissement
+public à caractère scientifique et technologique, dont le siège est
+situé 3 rue Michel-Ange, 75794 Paris cedex 16.
+
+Institut National de Recherche en Informatique et en Automatique -
+INRIA, établissement public à caractère scientifique et technologique,
+dont le siège est situé Domaine de Voluceau, Rocquencourt, BP 105, 78153
+Le Chesnay cedex.
+
+
+ Préambule
+
+Ce contrat est une licence de logiciel libre dont l'objectif est de
+conférer aux utilisateurs la liberté de modification et de
+redistribution du logiciel régi par cette licence dans le cadre d'un
+modèle de diffusion en logiciel libre.
+
+L'exercice de ces libertés est assorti de certains devoirs à la charge
+des utilisateurs afin de préserver ce statut au cours des
+redistributions ultérieures.
+
+L'accessibilité au code source et les droits de copie, de modification
+et de redistribution qui en découlent ont pour contrepartie de n'offrir
+aux utilisateurs qu'une garantie limitée et de ne faire peser sur
+l'auteur du logiciel, le titulaire des droits patrimoniaux et les
+concédants successifs qu'une responsabilité restreinte.
+
+A cet égard l'attention de l'utilisateur est attirée sur les risques
+associés au chargement, à l'utilisation, à la modification et/ou au
+développement et à la reproduction du logiciel par l'utilisateur étant
+donné sa spécificité de logiciel libre, qui peut le rendre complexe à
+manipuler et qui le réserve donc à des développeurs ou des
+professionnels avertis possédant des connaissances informatiques
+approfondies. Les utilisateurs sont donc invités à charger et tester
+l'adéquation du logiciel à leurs besoins dans des conditions permettant
+d'assurer la sécurité de leurs systèmes et/ou de leurs données et, plus
+généralement, à l'utiliser et l'exploiter dans les mêmes conditions de
+sécurité. Ce contrat peut être reproduit et diffusé librement, sous
+réserve 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 décide 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: désigne le présent contrat de licence, ses éventuelles versions
+postérieures et annexes.
+
+Logiciel: désigne le logiciel sous sa forme de Code Objet et/ou de Code
+Source et le cas échéant sa documentation, dans leur état au moment de
+l'acceptation du Contrat par le Licencié.
+
+Logiciel Initial: désigne le Logiciel sous sa forme de Code Source et
+éventuellement de Code Objet et le cas échéant sa documentation, dans
+leur état au moment de leur première diffusion sous les termes du Contrat.
+
+Logiciel Modifié: désigne le Logiciel modifié par au moins une
+Contribution.
+
+Code Source: désigne l'ensemble des instructions et des lignes de
+programme du Logiciel et auquel l'accès est nécessaire en vue de
+modifier le Logiciel.
+
+Code Objet: désigne les fichiers binaires issus de la compilation du
+Code Source.
+
+Titulaire: désigne le ou les détenteurs des droits patrimoniaux d'auteur
+sur le Logiciel Initial.
+
+Licencié: désigne le ou les utilisateurs du Logiciel ayant accepté le
+Contrat.
+
+Contributeur: désigne le Licencié auteur d'au moins une Contribution.
+
+Concédant: désigne le Titulaire ou toute personne physique ou morale
+distribuant le Logiciel sous le Contrat.
+
+Contribution: désigne l'ensemble des modifications, corrections,
+traductions, adaptations et/ou nouvelles fonctionnalités intégrées dans
+le Logiciel par tout Contributeur, ainsi que tout Module Interne.
+
+Module: désigne un ensemble de fichiers sources y compris leur
+documentation qui permet de réaliser des fonctionnalités ou services
+supplémentaires à ceux fournis par le Logiciel.
+
+Module Externe: désigne tout Module, non dérivé du Logiciel, tel que ce
+Module et le Logiciel s'exécutent dans des espaces d'adressage
+différents, l'un appelant l'autre au moment de leur exécution.
+
+Module Interne: désigne tout Module lié au Logiciel de telle sorte
+qu'ils s'exécutent dans le même espace d'adressage.
+
+GNU GPL: désigne la GNU General Public License dans sa version 2 ou
+toute version ultérieure, telle que publiée par Free Software Foundation
+Inc.
+
+Parties: désigne collectivement le Licencié et le Concédant.
+
+Ces termes s'entendent au singulier comme au pluriel.
+
+
+ Article 2 - OBJET
+
+Le Contrat a pour objet la concession par le Concédant au Licencié d'une
+licence non exclusive, cessible et mondiale du Logiciel telle que
+définie ci-après à l'article 5 pour toute la durée de protection des droits
+portant sur ce Logiciel.
+
+
+ Article 3 - ACCEPTATION
+
+3.1 L'acceptation par le Licencié des termes du Contrat est réputée
+acquise du fait du premier des faits suivants:
+
+ * (i) le chargement du Logiciel par tout moyen notamment par
+ téléchargement à 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 concédés par le Contrat.
+
+3.2 Un exemplaire du Contrat, contenant notamment un avertissement
+relatif aux spécificités du Logiciel, à la restriction de garantie et à
+la limitation à un usage par des utilisateurs expérimentés a été mis à
+disposition du Licencié préalablement à son acceptation telle que
+définie à l'article 3.1 ci dessus et le Licencié reconnaît 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 définie en 3.1.
+
+
+ 4.2 DUREE
+
+Le Contrat produira ses effets pendant toute la durée légale de
+protection des droits patrimoniaux portant sur le Logiciel.
+
+
+ Article 5 - ETENDUE DES DROITS CONCEDES
+
+Le Concédant concède au Licencié, qui accepte, les droits suivants sur
+le Logiciel pour toutes destinations et pour la durée du Contrat dans
+les conditions ci-après détaillées.
+
+Par ailleurs, si le Concédant détient ou venait à détenir un ou
+plusieurs brevets d'invention protégeant tout ou partie des
+fonctionnalités du Logiciel ou de ses composants, il s'engage à ne pas
+opposer les éventuels droits conférés par ces brevets aux Licenciés
+successifs qui utiliseraient, exploiteraient ou modifieraient le
+Logiciel. En cas de cession de ces brevets, le Concédant s'engage à
+faire reprendre les obligations du présent alinéa aux cessionnaires.
+
+
+ 5.1 DROIT D'UTILISATION
+
+Le Licencié est autorisé à utiliser le Logiciel, sans restriction quant
+aux domaines d'application, étant ci-après précisé 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'exécution, 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 déterminer les idées et principes qui sont
+ à la base de n'importe quel élément de ce Logiciel; et ceci,
+ lorsque le Licencié effectue toute opération de chargement,
+ d'affichage, d'exécution, 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 résultant.
+
+Le Licencié est autorisé à apporter toute Contribution au Logiciel sous
+réserve de mentionner, de façon explicite, son nom en tant qu'auteur de
+cette Contribution et la date de création 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
+onéreux ou gratuit, un ou des exemplaires du Logiciel par tout procédé.
+
+Le Licencié est autorisé à distribuer des copies du Logiciel, modifié ou
+non, à des tiers dans les conditions ci-après détaillées.
+
+
+ 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 accompagnée:
+
+ 1. d'un exemplaire du Contrat,
+
+ 2. d'un avertissement relatif à la restriction de garantie et de
+ responsabilité du Concédant telle que prévue aux articles 8
+ et 9,
+
+et que, dans le cas où seul le Code Objet du Logiciel est redistribué,
+le Licencié permette aux futurs Licenciés d'accéder facilement au Code
+Source complet du Logiciel en indiquant les modalités d'accès, étant
+entendu que le coût additionnel d'acquisition du Code Source ne devra
+pas excéder le simple coût de transfert des données.
+
+
+ 5.3.2 DISTRIBUTION DU LOGICIEL MODIFIE
+
+Lorsque le Licencié apporte une Contribution au Logiciel, les conditions
+de distribution du Logiciel Modifié en résultant sont alors soumises à
+l'intégralité 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
+accompagnée:
+
+ 1. d'un exemplaire du Contrat,
+
+ 2. d'un avertissement relatif à la restriction de garantie et de
+ responsabilité du Concédant telle que prévue 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 Licenciés d'accéder
+facilement au code source complet du Logiciel Modifié en indiquant les
+modalités d'accès, étant entendu que le coût additionnel d'acquisition
+du code source ne devra pas excéder le simple coût de transfert des données.
+
+
+ 5.3.3 DISTRIBUTION DES MODULES EXTERNES
+
+Lorsque le Licencié a développé un Module Externe les conditions du
+Contrat ne s'appliquent pas à ce Module Externe, qui peut être distribué
+sous un contrat de licence différent.
+
+
+ 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 même 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 même version de la licence GNU GPL.
+
+
+ Article 6 - PROPRIETE INTELLECTUELLE
+
+
+ 6.1 SUR LE LOGICIEL INITIAL
+
+Le Titulaire est détenteur 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 régi
+par le Contrat et ce, pour la durée visée à l'article 4.2.
+
+
+ 6.2 SUR LES CONTRIBUTIONS
+
+Le Licencié qui a développé une Contribution est titulaire sur celle-ci
+des droits de propriété intellectuelle dans les conditions définies par
+la législation applicable.
+
+
+ 6.3 SUR LES MODULES EXTERNES
+
+Le Licencié qui a développé un Module Externe est titulaire sur celui-ci
+des droits de propriété intellectuelle dans les conditions définies par
+la législation applicable et reste libre du choix du contrat régissant
+sa diffusion.
+
+
+ 6.4 DISPOSITIONS COMMUNES
+
+Le Licencié s'engage expressément:
+
+ 1. à ne pas supprimer ou modifier de quelque manière que ce soit les
+ mentions de propriété intellectuelle apposées sur le Logiciel;
+
+ 2. à reproduire à l'identique lesdites mentions de propriété
+ intellectuelle sur les copies du Logiciel modifié ou non.
+
+Le Licencié s'engage à ne pas porter atteinte, directement ou
+indirectement, aux droits de propriété intellectuelle du Titulaire et/ou
+des Contributeurs sur le Logiciel et à prendre, le cas échéant, à
+l'égard de son personnel toutes les mesures nécessaires pour assurer le
+respect des dits droits de propriété intellectuelle du Titulaire et/ou
+des Contributeurs.
+
+
+ Article 7 - SERVICES ASSOCIES
+
+7.1 Le Contrat n'oblige en aucun cas le Concédant à la réalisation de
+prestations d'assistance technique ou de maintenance du Logiciel.
+
+Cependant le Concédant 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 déterminés dans un acte séparé. Ces actes de
+maintenance et/ou assistance technique n'engageront que la seule
+responsabilité du Concédant qui les propose.
+
+7.2 De même, tout Concédant est libre de proposer, sous sa seule
+responsabilité, à ses licenciés 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 modalités
+financières de son application feront l'objet d'un acte séparé entre le
+Concédant et le Licencié.
+
+
+ Article 8 - RESPONSABILITE
+
+8.1 Sous réserve des dispositions de l'article 8.2, le Licencié a la
+faculté, sous réserve de prouver la faute du Concédant concerné, de
+solliciter la réparation du préjudice direct qu'il subirait du fait du
+Logiciel et dont il apportera la preuve.
+
+8.2 La responsabilité du Concédant est limitée aux engagements pris en
+application du Contrat et ne saurait être engagée en raison notamment:
+(i) des dommages dus à l'inexécution, totale ou partielle, de ses
+obligations par le Licencié, (ii) des dommages directs ou indirects
+découlant de l'utilisation ou des performances du Logiciel subis par le
+Licencié et (iii) plus généralement d'un quelconque dommage indirect. En
+particulier, les Parties conviennent expressément que tout préjudice
+financier ou commercial (par exemple perte de données, perte de
+bénéfices, perte d'exploitation, perte de clientèle ou de commandes,
+manque à gagner, trouble commercial quelconque) ou toute action dirigée
+contre le Licencié par un tiers, constitue un dommage indirect et
+n'ouvre pas droit à réparation par le Concédant.
+
+
+ Article 9 - GARANTIE
+
+9.1 Le Licencié reconnaît 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 vérifier toutes les
+utilisations ni de détecter l'existence d'éventuels défauts. L'attention
+du Licencié a été attirée sur ce point sur les risques associés au
+chargement, à l'utilisation, la modification et/ou au développement et à
+la reproduction du Logiciel qui sont réservés à des utilisateurs avertis.
+
+Il relève de la responsabilité du Licencié de contrôler, par tous
+moyens, l'adéquation 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 Concédant déclare de bonne foi être en droit de concéder
+l'ensemble des droits attachés au Logiciel (comprenant notamment les
+droits visés à l'article 5).
+
+9.3 Le Licencié reconnaît que le Logiciel est fourni "en l'état" par le
+Concédant sans autre garantie, expresse ou tacite, que celle prévue à
+l'article 9.2 et notamment sans aucune garantie sur sa valeur commerciale,
+son caractère sécurisé, innovant ou pertinent.
+
+En particulier, le Concédant 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 Concédant ne garantit pas, de manière expresse ou tacite, que le
+Logiciel ne porte pas atteinte à un quelconque droit de propriété
+intellectuelle d'un tiers portant sur un brevet, un logiciel ou sur tout
+autre droit de propriété. Ainsi, le Concédant exclut toute garantie au
+profit du Licencié contre les actions en contrefaçon qui pourraient être
+diligentées au titre de l'utilisation, de la modification, et de la
+redistribution du Logiciel. Néanmoins, si de telles actions sont
+exercées contre le Licencié, le Concédant lui apportera son aide
+technique et juridique pour sa défense. Cette aide technique et
+juridique est déterminée au cas par cas entre le Concédant concerné et
+le Licencié dans le cadre d'un protocole d'accord. Le Concédant dégage
+toute responsabilité quant à l'utilisation de la dénomination du
+Logiciel par le Licencié. Aucune garantie n'est apportée quant à
+l'existence de droits antérieurs 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 Concédant pourra résilier de plein droit le
+Contrat trente (30) jours après notification adressée au Licencié et
+restée sans effet.
+
+10.2 Le Licencié dont le Contrat est résilié n'est plus autorisé à
+utiliser, modifier ou distribuer le Logiciel. Cependant, toutes les
+licences qu'il aura concédées antérieurement à la résiliation du Contrat
+resteront valides sous réserve qu'elles aient été effectuées 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 défaillance
+d'exécution du Contrat qui serait dû à un cas de force majeure, un cas
+fortuit ou une cause extérieure, telle que, notamment, le mauvais
+fonctionnement ou les interruptions du réseau électrique ou de
+télécommunication, la paralysie du réseau liée à une attaque
+informatique, l'intervention des autorités gouvernementales, les
+catastrophes naturelles, les dégâts des eaux, les tremblements de terre,
+le feu, les explosions, les grèves 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 prévaloir d'une ou plusieurs dispositions du
+Contrat, ne pourra en aucun cas impliquer renonciation par la Partie
+intéressée à s'en prévaloir ultérieurement.
+
+11.3 Le Contrat annule et remplace toute convention antérieure, écrite
+ou orale, entre les Parties sur le même 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 signée par leurs représentants dûment habilités.
+
+11.4 Dans l'hypothèse où une ou plusieurs des dispositions du Contrat
+s'avèrerait contraire à une loi ou à un texte applicable, existants ou
+futurs, cette loi ou ce texte prévaudrait, et les Parties feraient les
+amendements nécessaires pour se conformer à cette loi ou à ce texte.
+Toutes les autres dispositions resteront en vigueur. De même, la
+nullité, pour quelque raison que ce soit, d'une des dispositions du
+Contrat ne saurait entraîner la nullité de l'ensemble du Contrat.
+
+
+ 11.5 LANGUE
+
+Le Contrat est rédigé en langue française et en langue anglaise, ces
+deux versions faisant également foi.
+
+
+ Article 12 - NOUVELLES VERSIONS DU CONTRAT
+
+12.1 Toute personne est autorisée à copier et distribuer des copies de
+ce Contrat.
+
+12.2 Afin d'en préserver la cohérence, le texte du Contrat est protégé
+et ne peut être modifié que par les auteurs de la licence, lesquels se
+réservent le droit de publier périodiquement des mises à jour ou de
+nouvelles versions du Contrat, qui posséderont chacune un numéro
+distinct. Ces versions ultérieures seront susceptibles de prendre en
+compte de nouvelles problématiques rencontrées par les logiciels libres.
+
+12.3 Tout Logiciel diffusé sous une version donnée du Contrat ne pourra
+faire l'objet d'une diffusion ultérieure que sous la même version du
+Contrat ou une version postérieure, sous réserve des dispositions de
+l'article 5.3.4.
+
+
+ Article 13 - LOI APPLICABLE ET COMPETENCE TERRITORIALE
+
+13.1 Le Contrat est régi par la loi française. Les Parties conviennent
+de tenter de régler à l'amiable les différends ou litiges qui
+viendraient à se produire par suite ou à l'occasion du Contrat.
+
+13.2 A défaut d'accord amiable dans un délai de deux (2) mois à compter
+de leur survenance et sauf situation relevant d'une procédure d'urgence,
+les différends ou litiges seront portés par la Partie la plus diligente
+devant les Tribunaux compétents 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 Française (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) <cloudstrife@cpcscene.com>.
+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) <cloudstrife@cpcscene.com>.
+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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+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 mémoire %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 <stdio.h>
+#include <stdlib.h>
+#include <png.h>
+#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 défaut :
+ 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 <stdio.h>
+#include <stdlib.h>
+#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
--- /dev/null
+++ b/tools/hex2bin-2.0/bin/.deleteme
diff --git a/tools/hex2bin-2.0/bin/hex2bin b/tools/hex2bin-2.0/bin/hex2bin
new file mode 100755
index 0000000..c6967d7
--- /dev/null
+++ b/tools/hex2bin-2.0/bin/hex2bin
Binary files differ
diff --git a/tools/hex2bin-2.0/bin/mot2bin b/tools/hex2bin-2.0/bin/mot2bin
new file mode 100755
index 0000000..18400f4
--- /dev/null
+++ b/tools/hex2bin-2.0/bin/mot2bin
Binary files 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
+<crc-8-atm>
+ Name : "CRC-8"
+ Width : 8
+ Poly : 07
+ Init : 00
+ RefIn : False
+ RefOut : False
+ XorOut : 00
+ Check : F4
+
+<crc-8-itu>
+ Name : "CRC-8/ITU"
+ Width : 8
+ Poly : 07
+ Init : 00
+ RefIn : False
+ RefOut : False
+ XorOut : 55
+ Check : A1
+
+<crc-8-rohc>
+ Name : "CRC-8/ROHC"
+ Width : 8
+ Poly : 07
+ Init : FF
+ RefIn : True
+ RefOut : True
+ XorOut : 0
+ Check : D0
+
+39
+<crc-8-darc>
+ Name : "CRC-8/DARC"
+ Width : 8
+ Poly : 39
+ Init : 00
+ RefIn : True
+ RefOut : True
+ XorOut : 00
+ Check : 15
+
+1D
+<crc-8-icode>
+ Name : "CRC-8/I-CODE"
+ Width : 8
+ Poly : 1D
+ Init : FD
+ RefIn : False
+ RefOut : False
+ XorOut : 00
+ Check : 7E
+
+<crc-8-j1850>
+ Name : "CRC-8/J1850" (new entry)
+ Width : 8
+ Poly : 1D
+ Init : FF
+ RefIn : False
+ RefOut : False
+ XorOut : FF
+ Check : 4B
+
+31
+<crc-8-maxim>
+ Name : "CRC-8/MAXIM"
+ Alias : "DOW-CRC"
+ Width : 8
+ Poly : 31
+ Init : 00
+ RefIn : True
+ RefOut : True
+ XorOut : 00
+ Check : A1
+
+9B
+<crc-8-wcdma>
+ Name : "CRC-8/WCDMA"
+ Width : 8
+ Poly : 9B
+ Init : 00
+ RefIn : True
+ RefOut : True
+ XorOut : 00
+ Check : 25
+
+8D
+<crc-8-ccitt>
+ Name : "CRC-8/CCITT" (new entry) 1-Wire?
+ Width : 8
+ Poly : 8D
+ Init : 00?
+ RefIn : False?
+ RefOut : False?
+ XorOut : 00?
+ Check : D2
+
+D5
+<crc-8>
+ Name : "CRC-8" (new entry)
+ Width : 8
+ Poly : D5
+ Init : 00?
+ RefIn : False?
+ RefOut : False?
+ XorOut : 00?
+ Check : BC
+
+CRC-16
+8005
+<crc-16>
+ 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
+
+<crc-16-buypass>
+ Name : "CRC-16/BUYPASS"
+ Alias : "CRC-16/VERIFONE"
+ Width : 16
+ Poly : 8005
+ Init : 0000
+ RefIn : False
+ RefOut : False
+ XorOut : 0000
+ Check : FEE8
+
+<crc-dds-110>
+ Name : "CRC-16/DDS-110"
+ Width : 16
+ Poly : 8005
+ Init : 800D
+ RefIn : False
+ RefOut : False
+ XorOut : 0000
+ Check : 9ECF
+ XCheck : CFE9
+
+<crc-16-maxim>
+ Name : "CRC-16/MAXIM"
+ Width : 16
+ Poly : 8005
+ Init : 0000
+ RefIn : True
+ RefOut : True
+ XorOut : FFFF
+ Check : 44C2
+
+<crc-usb>
+ Name : "CRC-16/USB"
+ Width : 16
+ Poly : 8005
+ Init : FFFF
+ RefIn : True
+ RefOut : True
+ XorOut : FFFF
+ Check : B4C8
+
+<crc-modbus>
+ Name : "MODBUS"
+ Width : 16
+ Poly : 8005
+ Init : FFFF
+ RefIn : True
+ RefOut : True
+ XorOut : 0000
+ Check : 4B37
+
+1021
+<crc-ccitt-1d0f>
+ Name : "CRC-16/AUG-CCITT"
+ Alias : "CRC-16/SPI-FUJITSU"
+ Width : 16
+ Poly : 1021
+ Init : 1D0F
+ RefIn : False
+ RefOut : False
+ XorOut : 0000
+ Check : E5CC
+
+<crc-ccitt-ffff>
+ Name : "CRC-16/CCITT-FALSE"
+ Width : 16
+ Poly : 1021
+ Init : FFFF
+ RefIn : False
+ RefOut : False
+ XorOut : 0000
+ Check : 29B1
+
+<crc-genibus>
+ 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
+
+<crc-ccitt-xmodem>
+ Name : "XMODEM"
+ Alias : "ZMODEM"
+ Alias : "CRC-16/ACORN"
+ Width : 16
+ Poly : 1021
+ Init : 0000
+ RefIn : False
+ RefOut : False
+ XorOut : 0000
+ Check : 31C3
+
+<crc-mcrf4xx>
+ Name : "CRC-16/MCRF4XX"
+ Width : 16
+ Poly : 1021
+ Init : FFFF
+ RefIn : True
+ RefOut : True
+ XorOut : 0000
+ Check : 6F91
+
+<crc-riello>
+ Name : "CRC-16/RIELLO"
+ Width : 16
+ Poly : 1021
+ Init : B2AA
+ RefIn : True
+ RefOut : True
+ XorOut : 0000
+ Check : 63D0
+
+ <crc-ccitt-kermit>
+ 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
+
+<crc-x25>
+ 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
+<crc-dect-r>
+ Name : "CRC-16/DECT-R"
+ Alias : "R-CRC-16"
+ Width : 16
+ Poly : 0589
+ Init : 0000
+ RefIn : False
+ RefOut : False
+ XorOut : 0001
+ Check : 007E
+
+<crc-dect-x>
+ Name : "CRC-16/DECT-X"
+ Alias : "X-CRC-16"
+ Width : 16
+ Poly : 0589
+ Init : 0000
+ RefIn : False
+ RefOut : False
+ XorOut : 0000
+ Check : 007F
+
+3D65
+<crc-dnp>
+ Name : "CRC-16/DNP"
+ Width : 16
+ Poly : 3D65
+ Init : 0000
+ RefIn : True
+ RefOut : True
+ XorOut : FFFF
+ Check : EA82
+ XCheck : 82EA
+
+<crc-en-13757>
+ Name : "CRC-16/EN-13757"
+ Width : 16
+ Poly : 3D65
+ Init : 0000
+ RefIn : False
+ RefOut : False
+ XorOut : FFFF
+ Check : C2B7
+
+8BB7
+<crc-t10-dif>
+ Name : "CRC-16/T10-DIF"
+ Width : 16
+ Poly : 8BB7
+ Init : 0000
+ RefIn : False
+ RefOut : False
+ XorOut : 0000
+ Check : D0DB
+
+A097
+<crc-teledisk>
+ Name : "CRC-16/TELEDISK"
+ Width : 16
+ Poly : A097
+ Init : 0000
+ RefIn : False
+ RefOut : False
+ XorOut : 0000
+ Check : 0FB3
+
+CRC-24
+864CFB
+<crc-24>
+ Name : "CRC-24"
+ Alias : "CRC-24/OPENPGP"
+ Width : 24
+ Poly : 864CFB
+ Init : B704CE
+ RefIn : False
+ RefOut : False
+ XorOut : 000000
+ Check : 21CF02
+
+5D6DCB
+<crc-24-flexray-a>
+ Name : "CRC-24/FLEXRAY-A"
+ Width : 24
+ Poly : 5D6DCB
+ Init : FEDCBA
+ RefIn : False
+ RefOut : False
+ XorOut : 000000
+ Check : 7979BD
+
+<crc-24-flexray-b>
+ Name : "CRC-24/FLEXRAY-B"
+ Width : 24
+ Poly : 5D6DCB
+ Init : ABCDEF
+ RefIn : False
+ RefOut : False
+ XorOut : 000000
+ Check : 1F23B8
+
+CRC-32
+04C11DB7
+<crc-32>
+ Name : "CRC-32"
+ Alias : "CRC-32/ADCCP"
+ Alias : "PKZIP"
+ Width : 32
+ Poly : 04C11DB7
+ Init : FFFFFFFF
+ RefIn : True
+ RefOut : True
+ XorOut : FFFFFFFF
+ Check : CBF43926
+
+<crc-32-bzip2>
+ Name : "CRC-32/BZIP2"
+ Alias : "B-CRC-32"
+ Width : 32
+ Poly : 04C11DB7
+ Init : FFFFFFFF
+ RefIn : False
+ RefOut : False
+ XorOut : FFFFFFFF
+ Check : FC891918
+
+<crc-32-mpeg-2>
+ Name : "CRC-32/MPEG-2"
+ Width : 32
+ Poly : 04C11DB7
+ Init : FFFFFFFF
+ RefIn : False
+ RefOut : False
+ XorOut : 00000000
+ Check : 0376E6E7
+
+<crc-32-posix>
+ Name : "CRC-32/POSIX"
+ Alias : "CKSUM"
+ Width : 32
+ Poly : 04C11DB7
+ Init : 00000000
+ RefIn : False
+ RefOut : False
+ XorOut : FFFFFFFF
+ Check : 765E7680
+ LCheck : 377A6011
+
+<crc-32-jamcrc>
+ Name : "JAMCRC"
+ Width : 32
+ Poly : 04C11DB7
+ Init : FFFFFFFF
+ RefIn : True
+ RefOut : True
+ XorOut : 00000000
+ Check : 340BC6D9
+
+1EDC6F41
+<crc-32-C>
+ 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
+<crc-32-D>
+ Name : "CRC-32D"
+ Width : 32
+ Poly : A833982B
+ Init : FFFFFFFF
+ RefIn : True
+ RefOut : True
+ XorOut : FFFFFFFF
+ Check : 87315576
+
+741B8CD7
+<crc-32-K> (new entry)
+ Name : "CRC-32K"
+ Alias : "CRC-32/KOOPMAN"
+ Width : 32
+ Poly : 741B8CD7
+ Init : 00000000?
+ RefIn : False?
+ RefOut : False?
+ XorOut : 00000000?
+ Check : 085A3197 ?
+
+814141AB
+<crc-32-Q>
+ Name : "CRC-32Q"
+ Width : 32
+ Poly : 814141AB
+ Init : 00000000
+ RefIn : False
+ RefOut : False
+ XorOut : 00000000
+ Check : 3010BF7F
+
+000000AF
+<crc-32-xfer>
+ Name : "XFER"
+ Width : 32
+ Poly : 000000AF
+ Init : 00000000
+ RefIn : False
+ RefOut : False
+ XorOut : 00000000
+ Check : BD0BE338
+
+CRC-40
+<crc-40-gsm>
+ Name : "CRC-40/GSM"
+ Width : 40
+ Poly : 0004820009
+ Init : 0000000000
+ RefIn : False
+ RefOut : False
+ XorOut : 0000000000
+ Check : 2BE9B039B9
+
+CRC-64
+42F0E1EBA9EA3693
+<crc-64>
+ Name : "CRC-64"
+ Width : 64
+ Poly : 42F0E1EBA9EA3693
+ Init : 0000000000000000
+ RefIn : False
+ RefOut : False
+ XorOut : 0000000000000000
+ Check : 6C40DF5F0B497347
+
+<crc-64-we>
+ Name : "CRC-64/WE"
+ Width : 64
+ Poly : 42F0E1EBA9EA3693
+ Init : FFFFFFFFFFFFFFFF
+ RefIn : False
+ RefOut : False
+ XorOut : FFFFFFFFFFFFFFFF
+ Check : 62EC59E3F1A4F00A
+
+000000000000001B
+<crc-64-1b>
+ Name : "CRC-64/1B" (New entry)
+ Width : 64
+ Poly : 000000000000001B
+ Init : 0000000000000000
+ RefIn : True
+ RefOut : True
+ XorOut : 0000000000000000
+ Check : 46A5A9388A5BEFFE
+
+AD93D23594C935A9
+<crc-64-jones>
+ 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* 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 <stdint.h>
+
+#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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#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<Hex2bin>
+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<Mot2bin>
+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<Ex.: hex2bin -c example.hex>
+
+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<t> or B<f> 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<filename.bin>.
+Another extension may be specified with this command:
+
+B<Ex.: hex2bin -e com example.hex>
+
+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<Ex.: hex2bin -p 3E example.hex>
+
+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<Ex.: hex2bin -s 0000 records_start_at_0100.hex>
+
+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 <stdint.h>
+
+#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 <iostream>
+using namespace std;
+#include <cmath>
+#include <cstring>
+#include <cstdio>
+#include <ctype.h>
+
+#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:"<<hex<<b<<endl;
+ return( BYTE )( BufFile[ Pos ] ^ ( DproBasic[ Pos & 0x7F ] * Deprotect ) );
+}
+
+
+int GetWord( BYTE * BufFile, int Pos, int Deprotect )
+{
+ int Ret = BufFile[ Pos ] ^ ( DproBasic[ Pos & 0x7F ] * Deprotect );
+ Pos++;
+ Ret += ( ( BufFile[ Pos ] ^ ( DproBasic[ Pos & 0x7F ] * Deprotect ) ) << 8 );
+ return( Ret );
+}
+
+
+//
+// Ajoute un "mot" (nom d'une variable, RSX...) dans la chaine "Listing"
+//
+int AddWord( BYTE * BufFile, int Pos, char * Listing, int Deprotect )
+{
+ int LenVar = 0, l = strlen( Listing );
+ BYTE b;
+
+ do
+ {
+ b = GetByte( BufFile, Pos++, Deprotect );
+ Listing[ l++ ] = ( char )( b & 0x7F );
+ }
+ while( ! ( b & 0x80 ) && LenVar++ < 0xFF );
+ Listing[ l ] = 0;
+ return( Pos );
+}
+
+
+//
+// Convertir le buffer en listing basic
+//
+void Basic( BYTE * BufFile, char * Listing, bool IsBasic, bool CrLf )
+{
+ static char Tmp[ 32 ];
+ int Pos = 0, Token = 0;
+ int StartLigne = 0, EndLigne;
+ char * p;
+ double f;
+ int exp;
+ int Deprotect=0;
+ //cout << BufFile <<endl;
+ static const char * Nbre[ 11 ] =
+ {
+ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"
+ };
+ static const char * MotsClefs[ 0x80 ] =
+ {
+ "AFTER", "AUTO", "BORDER", "CALL", "CAT", "CHAIN", "CLEAR", "CLG",
+ "CLOSEIN", "CLOSEOUT", "CLS", "CONT", "DATA", "DEF", "DEFINT",
+ "DEFREAL", "DEFSTR", "DEG", "DELETE", "DIM", "DRAW", "DRAWR", "EDIT",
+ "ELSE", "END", "ENT", "ENV", "ERASE", "ERROR", "EVERY", "FOR",
+ "GOSUB", "GOTO", "IF", "INK", "INPUT", "KEY", "LET", "LINE", "LIST",
+ "LOAD", "LOCATE", "MEMORY", "MERGE", "MID$", "MODE", "MOVE", "MOVER",
+ "NEXT", "NEW", "ON", "ON BREAK", "ON ERROR GOTO", "SQ", "OPENIN",
+ "OPENOUT", "ORIGIN", "OUT", "PAPER", "PEN", "PLOT", "PLOTR", "POKE",
+ "PRINT", "'", "RAD", "RANDOMIZE", "READ", "RELEASE", "REM", "RENUM",
+ "RESTORE", "RESUME", "RETURN", "RUN", "SAVE", "SOUND", "SPEED", "STOP",
+ "SYMBOL", "TAG", "TAGOFF", "TROFF", "TRON", "WAIT", "WEND", "WHILE",
+ "WIDTH", "WINDOW", "WRITE", "ZONE", "DI", "EI", "FILL", "GRAPHICS",
+ "MASK", "FRAME", "CURSOR", "#E2", "ERL", "FN", "SPC", "STEP", "SWAP",
+ "#E8", "#E9", "TAB", "THEN", "TO", "USING", ">", "=", ">=", "<", "<>",
+ "<=", "+", "-", "*", "/", "^", "\\ ", "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 : " <<Listing << endl;
+ if ( IsBasic )
+ {
+ int lg = GetWord( BufFile, Pos, Deprotect );
+ Pos += 2;
+ if ( ! lg )
+ break;
+
+ int NumLigne = GetWord( BufFile, Pos, Deprotect );
+ Pos += 2;
+ sprintf( Tmp, "%d ", NumLigne );
+ strcat( Listing, Tmp );
+ }
+ else
+ if ( ! Token || Token == 0x1A )
+ break;
+
+ int DansChaine = 0; // #### Hum, plus compliqué que ça je pense...
+ do
+ {
+ //cout << "Tmp:"<<Tmp<<endl;
+ Token = GetByte( BufFile, Pos++, Deprotect );
+ if ( ! IsBasic && Token == 0x1A )
+ break;
+
+ if ( DansChaine || ! IsBasic )
+ {
+ Tmp[ 0 ] = ( char )Token;
+ Tmp[ 1 ] = 0;
+ strcat( Listing, Tmp );
+ if ( Token == '"' )
+ DansChaine ^= 1;
+ // cout << " DansChaine Tmp:"<<Tmp<<endl;
+ }
+ else
+ if ( Token > 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 <<endl;
+ switch( Token )
+ {
+ case 0x01 :
+ Tmp[ 0 ] = ':';
+ Tmp[ 1 ] = 0;
+ strcat( Listing, Tmp );
+ break;
+
+ case 0x02 : // Variable entière (type %)
+ Pos = AddWord( BufFile
+ , 2 + Pos
+ , Listing
+ , Deprotect
+ );
+ strcat( Listing, "%" );
+ break;
+
+
+ case 0x03 : // Variable chaine (type $)
+ Pos = AddWord( BufFile
+ , 2 + Pos
+ , Listing
+ , Deprotect
+ );
+ strcat( Listing, "$" );
+ break;
+
+ case 0x0B :
+ case 0x0C :
+ case 0x0D : // Variable "standard"
+ Pos = AddWord( BufFile
+ , 2 + Pos
+ , Listing
+ , Deprotect
+ );
+ break;
+
+ case 0x19 : // Constante entière 8 bits
+ sprintf(Listing+strlen(Listing),"%d",(BYTE)GetByte( BufFile, Pos, Deprotect));
+ Pos++;
+ break;
+
+ case 0x1A :
+ case 0x1E : // Constante entière 16 bits
+ sprintf(Listing+strlen(Listing),"%d",GetWord( BufFile, Pos, Deprotect));
+ Pos += 2;
+ break;
+
+ case 0x1B :
+ sprintf( Tmp
+ , "&X%X"
+ , GetWord( BufFile, Pos, Deprotect )
+ );
+ strcat( Listing, Tmp );
+ Pos += 2;
+ break;
+
+ case 0x1C :
+ sprintf( Tmp
+ , "&%X"
+ , GetWord( BufFile, Pos, Deprotect )
+ );
+ strcat( Listing, Tmp );
+ Pos += 2;
+ break;
+
+ case 0x1F : // Constante flottante
+ f = ( GetByte( BufFile, Pos + 2, Deprotect ) << 16 )
+ + ( GetByte( BufFile, Pos + 1, Deprotect ) << 8 )
+ + GetByte( BufFile, Pos, Deprotect )
+ + ( ( GetByte( BufFile, Pos + 3, Deprotect ) & 0x7F ) << 24 );
+ f = 1 + ( f / 0x80000000 );
+
+ if ( GetByte( BufFile, Pos + 3, Deprotect ) & 0x80 )
+ f = -f;
+
+ exp = GetByte( BufFile, Pos + 4, Deprotect ) - 129;
+ Pos += 5;
+ sprintf( Tmp, "%f", f * pow( (double) 2, exp ) );
+ // Suppression des '0' inutiles
+ p = &Tmp[ strlen( Tmp ) - 1 ];
+ while( * p == '0' )
+ * p-- = 0;
+
+ if ( * p == '.' )
+ * p = 0;
+
+ strcat( Listing, Tmp );
+ break;
+
+ case 0x7C :
+ strcat( Listing, "|" );
+ Pos = AddWord( BufFile
+ , 1 + Pos
+ , Listing
+ , Deprotect
+ );
+ break;
+
+ case 0xFF :
+ if ( GetByte( BufFile, Pos, Deprotect ) < 0x80 )
+ strcat( Listing
+ , Fcts[ GetByte( BufFile
+ , Pos++
+ , Deprotect
+ )
+ ]
+ );
+ else
+ {
+ Tmp[ 1 ] = 0;
+ Tmp[ 0 ] = ( char )( GetByte( BufFile
+ , Pos++
+ , Deprotect
+ ) & 0x7F
+ );
+ strcat( Listing, Tmp );
+ }
+ break;
+
+ default :
+ Token = Token;
+ }
+ }
+ }
+ while( Token );
+ if ( CrLf )
+ {
+ //
+ // Retour à la ligne si > 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 <iostream>
+#include <cstdio>
+#include "MyType.h"
+#include "BitmapCPC.h"
+#include "GestDsk.h"
+#include <string>
+#include <cstring>
+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 <iostream>
+#include <cstdio>
+#include <cstring>
+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 <iostream>
+#include <cstdio>
+#include <cstring>
+
+#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 <iostream>
+#include <string.h>
+#include <cstdlib>
+#include <cstdio>
+#include <algorithm>
+#include <sstream>
+
+#include "MyType.h"
+#include "GestDsk.h"
+#include "endianPPC.h"
+#include "Outils.h"
+#include <cerrno>
+
+#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 );
+}
+
+
+
+//
+// CrŽe une en-tte AMSDOS par dŽfaut
+//
+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 entrŽe de rŽpertoire 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 donnŽes "brutes" de l'image disquette
+//
+unsigned char * DSK::GetRawData( int Pos ) {
+ return( &ImgDsk[ Pos ] );
+}
+
+
+//
+// Ecriture de donnŽes "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 dŽpassement 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 utilisŽs 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 entrŽe dans le rŽpertoire
+//
+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 )
+ );
+}
+
+
+//
+// VŽrifie 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'entrée pour mettre dans le catalogue
+ for ( PosFile = 0; PosFile < TailleFic; ) { //Pour chaque bloc du fichier
+ PosDir = RechercheDirLibre(); //Trouve une entrée libre dans le CAT
+ if ( PosDir != -1 ) {
+ DirLoc->User = UserNumber; //Remplit l'entrée : User 0
+ if(System_file) DirLoc->Nom[9]|=0x80;
+ if(Read_only) DirLoc->Nom[8]|=0x80;
+ DirLoc->NumPage = ( unsigned char )NbPages++; // Numéro de l'entrée 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 entrŽe du rŽpertoire
+//
+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 );
+}
+
+
+//
+// VŽrifier 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 "<<tr->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 "<<track<<"!" << endl;
+ // return( false );
+ }
+ if ( MinSect != MinSectFirst )
+ {
+ cout << "Warning : track "<<track<<" start at sector"<<MinSect<<" while track 0 starts at "<<MinSectFirst << endl;
+ //return( false );
+ }
+ }
+ return( true );
+ }
+ cout << "Multi-side dsk ! Expected 1 head, got " << (int)Infos->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 <<std::endl;
+
+ if ( ! littleToBig )
+ Infos->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 << "Création automatique d'une en-tête 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 déjà une en-tête\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 inutilisés par des 0 dans l'en-tête
+
+ 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 effacés
+ //
+ 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 <string>
+
+#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 <iostream>
+#include <cstdlib>
+#include <cstring>
+#include <algorithm> // 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<string> AmsdosFileList;
+
+ int exeAdress=0,loadAdress=0,AmsdosType=1, UserNumber=0;
+
+ DSK MyDsk;
+
+ IsDsk = IsDskValid = false;
+ IsDskSaved = true;
+
+ // Récupération 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 << ")."<<endl;
+ exit(EXIT_FAILURE);
+ }
+ if ( ! MyDsk.CheckDsk() ) {
+ cerr <<"Fichier image non supporté ("<< DskFile << ")."<<endl;
+ exit(EXIT_FAILURE);
+ }
+ int Indice;
+ for(vector<string>::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 !"<<endl;
+ else if ( ModeListHex ) {
+ MyDsk.Hexdecimal();
+ cout << Listing << endl;
+ }
+ else if ( ModeDisaFile )
+ cout << ViewDesass( )<<endl;
+ }
+ }
+
+ if(ModeNewDsk)
+ {
+ MyDsk.FormatDsk( 9, 42 );
+ if (! MyDsk.WriteDsk(DskFile))
+ {
+ cerr << "Error writing file " << DskFile << endl;
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if ( ModeListDsk ) { // lire Dsk
+ if ( ! MyDsk.ReadDsk(DskFile) ) {
+ cerr<< "Error reading file ("<< DskFile << ")."<<endl;
+ exit(EXIT_FAILURE);
+ }
+ if ( ! MyDsk.CheckDsk() ) {
+ cerr <<"Unsupported dsk file ("<< DskFile << ")."<<endl;
+ exit(EXIT_FAILURE);
+ }
+ cout << MyDsk.ReadDskDir();
+ }
+
+ if ( ModeImportFile ) { // Ajouter fichiers sur dsk
+ if ( ! MyDsk.ReadDsk(DskFile) ) {
+ cerr<< "Error reading file ("<< DskFile << ")."<<endl;
+ exit(EXIT_FAILURE);
+ }
+
+ if ( ! MyDsk.CheckDsk() ) {
+ cerr <<"Unsupported dsk file ("<< DskFile << ")."<<endl;
+ exit(EXIT_FAILURE);
+ }
+
+ for(vector<string>::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."<<endl;
+ cout << MyDsk.ReadDskDir();
+ exit(EXIT_SUCCESS);
+ }
+ }
+ else if(Force_Overwrite)
+ MyDsk.RemoveFile(Indice);
+
+ cerr << "Amsdos file : "<< *iter << endl;
+
+ MyDsk.PutFileInDsk(*iter,AmsdosType,loadAdress,exeAdress,UserNumber,System_file,Read_only);
+ }
+ if ( MyDsk.WriteDsk (DskFile) )
+ cout << MyDsk.ReadDskDir();
+ else cerr<< "Error writing file : " << DskFile << endl;
+ }
+
+ if ( ModeRemoveFile ) {
+ if ( ! MyDsk.ReadDsk( (char*)DskFile.c_str() ) ) {
+ cerr<< "Error reading file ("<< DskFile << ")."<<endl;
+ exit(EXIT_FAILURE);
+ }
+ if ( ! MyDsk.CheckDsk() ) {
+ cerr <<"unsupported DSK file ("<< DskFile << ")."<<endl;
+ exit(EXIT_FAILURE);
+ }
+ int Indice;
+ for(vector<string>::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 << ")."<<endl;
+ exit(EXIT_FAILURE);
+ }
+ if ( ! MyDsk.CheckDsk() ) {
+ cerr <<"Unsupported dsk ("<< DskFile << ")."<<endl;
+ exit(EXIT_FAILURE);
+ }
+ int Indice;
+
+ for(vector<string>::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 ("<<AmsdosFile<<")."<<endl;
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+
+ cerr << "------------------------------------" << endl;
+
+ return(EXIT_SUCCESS);
+}
+
+
+
+
+void help(void)
+{
+ cout <<endl;
+ cout << "--------------------------------------------------------------------------------" << endl;
+ cout << "################################################################################"<< endl;
+ cout << VERSION <<" (by Demoniak, Sid, PulkoMandy), http://github.com/cpcsdk " << endl;
+ cout << "################################################################################"<< endl;
+ cout << endl;
+ cout << "Usage : " << endl;
+ cout << "\t"<< PROGNAME << " <DSKfile> [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"<<endl;
+ cout << "-r : Remove file iDSK floppy.dsk -r myprog.bas" << endl;
+ cout << "-n : create New dsk file iDSK floppy2.dsk -n" << endl;
+ cout << "-z : disassemble a binary file iDSK floppy.dsk -z myprog.bin" << endl;
+ cout << "-b : list a Basic file iDSK floppy.dsk -b myprog.bas" << endl;
+ cout << "-d : list a Dams file iDSK floppy.dsk -d myprog.dms" << endl;
+ cout << "-h : list a binary file as Hexadecimal iDSK floppy.dsk -h myprog.bin" << endl;
+ cout << "-i : Import file iDSK floppy.dsk -i myprog.bas" << endl
+ << " -t : fileType (0=ASCII/1=BINARY) ... -t 1" << endl;
+ cout << " -e : hex Execute address of file ... -e C000 -t 1" << endl;
+ cout << " -c : hex loading address of file ... -e C000 -c 4000 -t 1" << endl;
+ cout << " -f : Force overwriting if file exists ... -f" << endl
+ << " -o : insert a read-Only file ... -o" << endl
+ << " -s : insert a System file ... -s" << endl
+ << " -u : insert file with User number ... -u 3" << endl;
+ cout << "--------------------------------------------------------------------------------" << endl;
+ cout << "Please report bugs ! - Demoniak/Sid/PulkoMandy" << endl;
+ exit (0);
+}
+
diff --git a/tools/iDSK/src/Main.h b/tools/iDSK/src/Main.h
new file mode 100644
index 0000000..d6d25b6
--- /dev/null
+++ b/tools/iDSK/src/Main.h
@@ -0,0 +1,19 @@
+#ifndef __MAIN_CPP__
+#define __MAIN_CPP__
+#define VERSION "iDSK version 0.16"
+#define PROGNAME "iDSK"
+char Nom[ 256 ];
+char Msg[ 128 ];
+StDirEntry TabDir[ 64 ];
+int PosItem[ 64 ];
+int Langue;
+bool IsDsk, IsDskValid, IsDskSaved;
+int TypeModeImport, TypeModeExport;
+
+
+
+void help(void);
+void DecomposeArg (char **argv,int argc);
+
+
+#endif
diff --git a/tools/iDSK/src/MyType.h b/tools/iDSK/src/MyType.h
new file mode 100644
index 0000000..132a1fd
--- /dev/null
+++ b/tools/iDSK/src/MyType.h
@@ -0,0 +1,19 @@
+#ifndef MYTYPE_H_
+#define MYTYPE_H_
+
+/* types definitions to be coherent with Visual Basic C++ types */
+
+typedef unsigned char BYTE; /* unsigned 8-bit type */
+typedef unsigned short WORD; /* unsigned 16-bit type */
+typedef unsigned long DWORD; /* unsigned 32-bit type */
+
+
+/* constant defintion usefull in the code */
+
+#define TRUE 1
+#define FALSE 0
+#define MODE_ASCII 0
+#define MODE_BINAIRE 1
+
+
+#endif /*MYTYPE_H_*/
diff --git a/tools/iDSK/src/Outils.cpp b/tools/iDSK/src/Outils.cpp
new file mode 100644
index 0000000..54e3c22
--- /dev/null
+++ b/tools/iDSK/src/Outils.cpp
@@ -0,0 +1,165 @@
+#include <iostream>
+#include <cstring>
+#include <cstdio>
+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["<<i<<"]:"<< Ascii[ i ] << endl;
+ }
+ else
+ {
+ Ascii[ i ] = '.';
+ }
+ if ( AddOffset && ( ! ( i & 0x0F ) ) )
+ {
+ Hex[ q++ ] = '#';
+ Hex[ q++ ] = CodeHexa[ Offset >> 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 <iostream>
+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 <iostream>
+#include <cstdlib>
+using namespace std;
+#include "endianPPC.h"
+
+#ifndef _MSC_VER
+#include <sys/param.h>
+#include <endian.h>
+#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 <fstream>
+
+#if __APPLE__
+#include <crt_externs.h>
+#define environ (*_NSGetEnviron())
+#elif _WIN32
+#include <Stdio.h>
+#define environ _environ
+#else
+#include <unistd.h>
+#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<std::string> args;
+ std::string arg;
+
+ while (ifile >> arg)
+ args.push_back(arg);
+
+ _parse(args);
+}
+
+GETOPT_INLINE void GetOpt_pp::_parse(const std::vector<std::string>& 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<std::string>& 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<std::string> 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<std::string> 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 <string>
+#include <vector> // candidate to be removed
+#include <map>
+#include <sstream>
+#include <list>
+
+/*
+ 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<std::string, OptionData> LongOptions;
+typedef std::map<char, OptionData> 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 <class T> 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<std::string>(const std::string& s, std::string& result, std::ios::fmtflags /*flags*/)
+{
+ result = s;
+ return _Option::OK;
+}
+
+
+template <class T> 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<T>& 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 T> class _OptionT : public _OptionTBase<T>
+{
+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<T>(option_token->value, this->target, flags);
+ }
+ }
+public:
+ _OptionT(const _OptionT<T>& other)
+ : _OptionTBase<T>(other)
+ {}
+
+ _OptionT(char short_opt, const std::string& long_opt, T& target)
+ : _OptionTBase<T>(short_opt, long_opt, target)
+ {}
+
+};
+
+template <class T> class _OptionT<std::vector<T> > : public _OptionTBase<std::vector<T> >
+{
+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<T>(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<std::vector<T> >& other)
+ : _OptionTBase<std::vector<T> >(other)
+ {}
+
+ _OptionT(char short_opt, const std::string& long_opt, std::vector<T>& target)
+ : _OptionTBase<std::vector<T> >(short_opt, long_opt, target)
+ {}
+};
+
+
+template <class T, class BaseOption>
+class _DefValOption : public BaseOption
+{
+ const T default_value;
+public:
+
+ _DefValOption(const _DefValOption<T, BaseOption>& 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 T>
+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<T>(token->value, target, flags);
+ }
+ else
+ return OptionNotFound;
+ }
+public:
+ _GlobalOption(const _GlobalOption<T>& other)
+ : target(other.target)
+ {}
+
+ _GlobalOption(T& target)
+ : target(target)
+ {}
+};
+
+template <class T>
+class _GlobalOption<std::vector<T> > : public _Option
+{
+ std::vector<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_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<T>(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<std::vector<T> >& other)
+ : target(other.target)
+ {}
+
+ _GlobalOption(std::vector<T>& target)
+ : target(target)
+ {}
+};
+
+template <class T>
+inline _OptionT<T> Option(char short_opt, const std::string& long_opt, T& target)
+{
+ return _OptionT<T>(short_opt, long_opt, target);
+}
+
+template <class T>
+inline _OptionT<T> Option(char short_opt, T& target)
+{
+ return _OptionT<T>(short_opt, std::string(), target);
+}
+
+// LongOpt only
+template <class T>
+inline _OptionT<T> Option(const std::string& long_opt, T& target)
+{
+ return _OptionT<T>(_Option::NO_SHORT_OPT, long_opt, target);
+}
+
+// Defaulted version
+template <class T>
+inline _DefValOption<T, _OptionT<T> >
+Option(char short_opt, const std::string& long_opt, T& target, const T& def)
+{
+ return _DefValOption<T, _OptionT<T> >(short_opt, long_opt, target, def);
+}
+
+template <class T>
+inline _DefValOption<T, _OptionT<T> > Option(char short_opt, T& target, const T& def)
+{
+ return _DefValOption<T, _OptionT<T> >(short_opt, std::string(), target, def);
+}
+
+// no short opt.
+template <class T>
+inline _DefValOption<T, _OptionT<T> >
+Option(const std::string& long_opt, T& target, const T& def)
+{
+ return _DefValOption<T, _OptionT<T> >(_Option::NO_SHORT_OPT, long_opt, target, def);
+}
+
+// Defaults for strings:
+inline _DefValOption<std::string, _OptionT<std::string> >
+Option(char short_opt, const std::string& long_opt, std::string& target, const char* def)
+{
+ return _DefValOption<std::string, _OptionT<std::string> >(short_opt, long_opt, target, def);
+}
+
+inline _OptionT<std::string> Option(char short_opt, std::string& target, const char* def)
+{
+ return _DefValOption<std::string, _OptionT<std::string> >(short_opt, std::string(), target, def);
+}
+
+// no short opt.
+inline _DefValOption<std::string, _OptionT<std::string> >
+Option(const std::string& long_opt, std::string& target, const char* def)
+{
+ return _DefValOption<std::string, _OptionT<std::string> >(_Option::NO_SHORT_OPT, long_opt, target, def);
+}
+
+// Global Option:
+template <class T>
+inline _GlobalOption<T> GlobalOption(T& target)
+{
+ return _GlobalOption<T>(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<std::string>& args);
+ GETOPT_INLINE void _parse_env();
+ static GETOPT_INLINE void _argc_argv_to_vector(int argc, const char* const* const argv, std::vector<std::string>& 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 <class T> 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 <class T> 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 <class T> inline T getopt(char short_opt) throw(GetOptEx)
+ {
+ T result;
+ operator >> (Option(short_opt, result));
+ return result;
+ }
+
+ template <class T> 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 Container, class Adapter, class OptionType>
+ 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<Container, Adapter, OptionType>& operator = (const _iterator<Container, Adapter, OptionType>& other)
+ {
+ _it = other._it;
+ _getopt_pp = other._getopt_pp;
+ return *this;
+ }
+
+ bool operator != (const _iterator<Container, Adapter, OptionType>& other) const
+ {
+ return _it != other._it;
+ }
+
+ OptionType option() const
+ {
+ return _it->first;
+ }
+ OptionType operator*() const
+ {
+ return option();
+ }
+
+ _iterator<Container, Adapter, OptionType>& operator ++()
+ {
+ ++_it;
+ return *this;
+ }
+
+ template <class T>
+ 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 <class T>
+ 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 <class T>
+ static void extract(T& t, GetOpt_pp& getopt_pp, const std::string& option)
+ {
+ getopt_pp >> Option('\0', option, t);
+ }
+ };
+
+ typedef _iterator<ShortOptions, ShortAdapter, char> short_iterator;
+ typedef _iterator<LongOptions, LongAdapter, const std::string&> 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 <jjm@usebox.net>",
+ )
+
+ 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 <jjm@usebox.net>",
+ )
+
+ 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 <jjm@usebox.net>",
+ )
+
+ 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 <stdio.h>
+#include <string.h>
+
+#include <ucl/ucl.h>
+
+#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
+