diff options
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 + @@ -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 Binary files differnew file mode 100644 index 0000000..b972271 --- /dev/null +++ b/font.gif 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>. @@ -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 Binary files differnew file mode 100644 index 0000000..b6b314b --- /dev/null +++ b/loading.png @@ -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 Binary files differnew file mode 100644 index 0000000..792862f --- /dev/null +++ b/menu.png diff --git a/mock.png b/mock.png Binary files differnew file mode 100644 index 0000000..d460bec --- /dev/null +++ b/mock.png diff --git a/music/board.mus b/music/board.mus Binary files differnew file mode 100644 index 0000000..b8b9039 --- /dev/null +++ b/music/board.mus diff --git a/music/gameover.mus b/music/gameover.mus Binary files differnew file mode 100644 index 0000000..d6d20ab --- /dev/null +++ b/music/gameover.mus diff --git a/music/intro.mus b/music/intro.mus Binary files differnew file mode 100644 index 0000000..0c66482 --- /dev/null +++ b/music/intro.mus diff --git a/music/return.mus b/music/return.mus Binary files differnew file mode 100644 index 0000000..0e4caac --- /dev/null +++ b/music/return.mus diff --git a/music/theplayer.mus b/music/theplayer.mus Binary files differnew file mode 100644 index 0000000..caf2703 --- /dev/null +++ b/music/theplayer.mus diff --git a/play.png b/play.png Binary files differnew file mode 100644 index 0000000..afb7531 --- /dev/null +++ b/play.png diff --git a/ship.png b/ship.png Binary files differnew file mode 100644 index 0000000..728d934 --- /dev/null +++ b/ship.png @@ -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 }; @@ -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 @@ -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 @@ -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 Binary files differnew file mode 100644 index 0000000..f6c9953 --- /dev/null +++ b/tiles-work.png diff --git a/tiles.png b/tiles.png Binary files differnew file mode 100644 index 0000000..eb7ca34 --- /dev/null +++ b/tiles.png diff --git a/tiles_alt.png b/tiles_alt.png Binary files differnew file mode 100644 index 0000000..e4e93f0 --- /dev/null +++ b/tiles_alt.png 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 Binary files differnew file mode 100755 index 0000000..c6967d7 --- /dev/null +++ b/tools/hex2bin-2.0/bin/hex2bin diff --git a/tools/hex2bin-2.0/bin/mot2bin b/tools/hex2bin-2.0/bin/mot2bin Binary files differnew file mode 100755 index 0000000..18400f4 --- /dev/null +++ b/tools/hex2bin-2.0/bin/mot2bin 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 + |