diff --git a/firmware/scroll/Makefile b/firmware/scroll/Makefile index 0a647a8..05d4616 100644 --- a/firmware/scroll/Makefile +++ b/firmware/scroll/Makefile @@ -13,6 +13,8 @@ include ../../sdk/common.mk +srcdir = . + INCLUDEDIR = ../../sdk/include FUENTEABIN = tools/build/FuenteABin$(EXESUFFIX) AS = sjasmplus @@ -27,35 +29,12 @@ endif AFLAGS += -I$(INCLUDEDIR) .PHONY: all -all: scroll.tap +all: $(srcdir)/scroll.tap -scroll.tap: scrolldesc.bin - GenTape $@ basic "SCROLL" 0 $< - -scrolldesc.bin: scrolldesc.asm define.asm scroll.bin.zx7b - $(AS) $(AFLAGS) --raw=$@ $< - -define.asm: scroll.bin scroll.exp - echo ' define filesize $(shell stat -c %s $<)' >$@ - cat scroll.exp >>$@ - -scroll.bin.zx7b: scroll.bin - zx7b $< $@ - -scroll.bin scroll.exp:\ - scroll.asm\ - string.asm\ - $(INCLUDEDIR)/playstc.inc\ - $(INCLUDEDIR)/filestc.def\ - $(INCLUDEDIR)/ay.def\ - music.stc\ - fuente6x8.bin\ - lineas.asm\ - fondo.rcs - $(AS) $(AFLAGS) --raw=scroll.bin --exp=scroll.exp $< - -fuente6x8.bin: fuente6x8.png | $(FUENTEABIN) - $(FUENTEABIN) $< $@ +$(srcdir)/fondo.rcs:\ + $(srcdir)/fondo.png\ + $(srcdir)/fondo.atr + Png2Rcs $< $@ -a $(srcdir)/fondo.atr $(FUENTEABIN): | tools ifeq ($(OS),Windows_NT) @@ -64,8 +43,39 @@ else $(MAKE) -w -C $| endif -fondo.rcs: fondo.png fondo.atr - Png2Rcs $< $@ -a fondo.atr +$(srcdir)/fuente6x8.bin: $(srcdir)/fuente6x8.png | $(FUENTEABIN) + $(FUENTEABIN) $< $@ + +$(srcdir)/scroll.exp\ +$(srcdir)/scroll.bin: $(srcdir)/scroll.asm\ + $(srcdir)/string.asm\ + $(INCLUDEDIR)/playstc.inc\ + $(INCLUDEDIR)/filestc.def\ + $(INCLUDEDIR)/ay.def\ + $(srcdir)/music.stc\ + $(srcdir)/fuente6x8.bin\ + $(srcdir)/lineas.asm\ + $(srcdir)/fondo.rcs + $(AS) $(AFLAGS) --exp=scroll.exp --raw=scroll.bin $< + +$(srcdir)/scroll.bin.zx7b: $(srcdir)/scroll.bin + zx7b $< $@ + +$(srcdir)/define.asm:\ + $(srcdir)/scroll.bin\ + $(srcdir)/scroll.exp + echo ' define filesize $(shell stat -c %s $<)' >$@ + cat $(srcdir)/scroll.exp >>$@ + +$(srcdir)/scrolldesc.bin:\ + $(srcdir)/scrolldesc.asm\ + $(srcdir)/define.asm\ + $(INCLUDEDIR)/dzx7b.mac\ + $(srcdir)/scroll.bin.zx7b + $(AS) $(AFLAGS) --raw=$@ $< + +$(srcdir)/scroll.tap: $(srcdir)/scrolldesc.bin + GenTape $@ basic "SCROLL" 0 $< .PHONY: install install:; @@ -76,7 +86,15 @@ uninstall:; .PHONY: clean clean: | tools $(MAKE) -w -C $| $@ - rm -f fuente6x8.bin fondo.rcs scroll.bin scroll.exp scroll.bin.zx7b define.asm scrolldesc.bin scroll.tap + rm -f\ + $(srcdir)/fuente6x8.bin\ + $(srcdir)/fondo.rcs\ + $(srcdir)/scroll.bin\ + $(srcdir)/scroll.exp\ + $(srcdir)/scroll.bin.zx7b\ + $(srcdir)/define.asm\ + $(srcdir)/scrolldesc.bin\ + $(srcdir)/scroll.tap .PHONY: distclean -distclean:; +distclean: clean diff --git a/firmware/scroll/scroll.asm b/firmware/scroll/scroll.asm index d6b66f4..9207e85 100644 --- a/firmware/scroll/scroll.asm +++ b/firmware/scroll/scroll.asm @@ -6,6 +6,8 @@ ; complete names. ; ; Copyright (C) 2016, 2017, 2020, 2021 Antonio Villena +; Contributors: +; 2021 Ivan Tatarinov ; ; 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 @@ -21,12 +23,14 @@ ; ; SPDX-FileCopyrightText: Copyright (C) 2016, 2017, 2020, 2021 Antonio Villena ; +; SPDX-FileContributor: 2021 Ivan Tatarinov +; ; SPDX-License-Identifier: GPL-3.0-only ; Compatible compilers: ; SJAsmPlus, - output scroll.bin +; output scroll.bin org $5e6d diff --git a/firmware/scroll/scroll.bat b/firmware/scroll/scroll.bat index fa9e9b0..6890814 100644 --- a/firmware/scroll/scroll.bat +++ b/firmware/scroll/scroll.bat @@ -1,17 +1,31 @@ -@rem SPDX-FileCopyrightText: 2016, 2021 Antonio Villena -@rem -@rem SPDX-License-Identifier: GPL-3.0-only -@call ..\..\sdk\setenv.bat -FuenteABin fuente6x8.png fuente6x8.bin +@echo off +rem SPDX-FileCopyrightText: 2016, 2021 Antonio Villena +rem +rem SPDX-FileContributor: 2021 Ivan Tatarinov +rem +rem SPDX-License-Identifier: GPL-3.0-only + +call ..\..\sdk\setenv.bat + +set FuenteABin=tools\build\FuenteABin +set AS=sjasmplus +set AFLAGS="-I%ZXSDK%\include" + +%FuenteABin% fuente6x8.png fuente6x8.bin Png2Rcs fondo.png fondo.rcs -a fondo.atr -sjasmplus scroll.asm -call :getfilesize scroll.bin -echo define filesize %_filesize% > define.asm +%AS% %AFLAGS% --exp=scroll.exp --raw=scroll.bin scroll.asm +call :getfilesize _filesize scroll.bin +echo define filesize %_filesize% > define.asm +type scroll.exp >> define.asm zx7b scroll.bin scroll.bin.zx7b -sjasmplus scrolldesc.asm +%AS% %AFLAGS% --raw=scrolldesc.bin scrolldesc.asm GenTape scroll.tap basic "SCROLL" 0 scrolldesc.bin + +rem Clean +del /q fuente6x8.bin fondo.rcs scroll.exp scroll.bin define.asm scroll.bin.zx7b scrolldesc.bin >nul + goto :eof :getfilesize -set _filesize=%~z1 +set %1=%~z2 goto :eof diff --git a/firmware/scroll/scrolldesc.asm b/firmware/scroll/scrolldesc.asm index 3a02e5f..00d1031 100644 --- a/firmware/scroll/scrolldesc.asm +++ b/firmware/scroll/scrolldesc.asm @@ -1,68 +1,32 @@ -; scrolldesc.asm +; scrolldesc.asm - loader of packed "scroll" demo. ; ; SPDX-FileCopyrightText: Copyright (C) 2016, 2017, 2020, 2021 Antonio Villena ; +; SPDX-FileContributor: 2021 Ivan Tatarinov +; ; SPDX-License-Identifier: GPL-3.0-only ; Compatible compilers: ; SJAsmPlus, +; output scrolldesc.bin + include define.asm - output scrolldesc.bin + include dzx7b.mac + org $5ccb + ld de, filestart+filesize-1 di defb $de, $c0, $37, $0e, $8f, $39, $96 - jr aqui -getbit ld a, (hl) - dec hl - adc a, a - ret -aqui ld hl, fin-1 -; ----------------------------------------------------------------------------- -; ZX7 Backwards by Einar Saukas, Antonio Villena -; Parameters: -; HL: source address (compressed data) -; DE: destination address (decompressing) -; ----------------------------------------------------------------------------- -dzx7b ld bc, $8000 - ld a, b -copyby inc c - ldd -mainlo add a, a - call z, getbit - jr nc, copyby - push de - ld d, c - defb $30 -lenval add a, a - call z, getbit - rl c - rl b - add a, a - call z, getbit - jr nc, lenval - inc c - jr z, exitdz - ld e, (hl) - dec hl - sll e - jr nc, offend - ld d, $10 -nexbit add a, a - call z, getbit - rl d - jr nc, nexbit - inc d - srl d -offend rr e - ex (sp), hl - ex de, hl - adc hl, de - lddr -exitdz pop hl - jr nc, mainlo + ld hl, scroll_end-1 + +dzx7b dzx7b_body getbit + jp start + +getbit dzx7b_getbit + incbin scroll.bin.zx7b -fin +scroll_end diff --git a/firmware/scroll/string.asm b/firmware/scroll/string.asm index ab47583..78dc490 100644 --- a/firmware/scroll/string.asm +++ b/firmware/scroll/string.asm @@ -259,6 +259,7 @@ dz $48, 'Sinclair Research Ltd' dz $48, 'LodePNG project' dz $48, 'SJAsmPlus project' + dz $48, 'Einar Saukas' dz $48, 'Xilinx Inc?' dz $48 dz $43, 'The ZX>UNO core team are' diff --git a/sdk/bin/dzx7b.exe b/sdk/bin/dzx7b.exe new file mode 100755 index 0000000..69b40c8 Binary files /dev/null and b/sdk/bin/dzx7b.exe differ diff --git a/sdk/bin/dzx7b.exe.license b/sdk/bin/dzx7b.exe.license new file mode 100644 index 0000000..331be09 --- /dev/null +++ b/sdk/bin/dzx7b.exe.license @@ -0,0 +1,11 @@ +SPDX-FileName: dzx7b.exe + +SPDX-FileType: BINARY + +SPDX-FileChecksum: SHA1: 1c1d766371864e10bfb5c95fa57d7598e8a6bf89 + +SPDX-FileCopyrightText: Copyright (c) 2015 Einar Saukas. All rights reserved. + +SPDX-License-Identifier: BSD-3-clause + +SPDX-FileComment: dzx7b version 1.0 (2015) - LZ77/LZSS backwards decompressor. diff --git a/sdk/include/dzx7b.mac b/sdk/include/dzx7b.mac new file mode 100644 index 0000000..89e9908 --- /dev/null +++ b/sdk/include/dzx7b.mac @@ -0,0 +1,71 @@ +; dzx7b.mac - ZX7 backwards decompressor macros. +; +; SPDX-FileCopyrightText: Copyright (C) 2016, 2021 Antonio Villena +; +; SPDX-FileNotice: Based on LZ77/LZSS backwards decompressor by Einar Saukas. +; SPDX-FileNotice: LZ77/LZSS backwards decompressor is Copyright (c) 2015 Einar Saukas. All rights reserved. +; SPDX-FileNotice: LZ77/LZSS backwards decompressor is distributed under BSD 3-Clause license. +; +; SPDX-License-Identifier: GPL-3.0-only + +; Compatible compilers: +; SJAsmPlus, + + ifndef dzx7b_mac_included + define dzx7b_mac_included + + macro dzx7b_getbit + ld a, (hl) + dec hl + adc a, a + ret + endm + +; ----------------------------------------------------------------------------- +; ZX7 Backwards by Einar Saukas, Antonio Villena +; Parameters: +; HL: source address (compressed data) +; DE: destination address (decompressing) +; ----------------------------------------------------------------------------- + macro dzx7b_body getbit_label + ld bc, $8000 + ld a, b +.copyby inc c + ldd +.mainlo add a, a + call z, getbit_label + jr nc, .copyby + push de + ld d, c + defb $30 ; 2 bytes opcode "jr nc, nn" but CY=1 and it is ignored with the following "add a, a" +.lenval add a, a ; 1 byte opcode + call z, getbit_label + rl c + rl b + add a, a + call z, getbit_label + jr nc, .lenval + inc c + jr z, .exitdz + ld e, (hl) + dec hl + sll e + jr nc, .offend + ld d, $10 +.nexbit add a, a + call z, getbit_label + rl d + jr nc, .nexbit + inc d + srl d +.offend rr e + ex (sp), hl + ex de, hl + adc hl, de + lddr +.exitdz pop hl + jr nc, .mainlo +; ret ; use it in source code to jump outside + endm + + endif ; !dzx7b_mac_included diff --git a/sdk/src/zx7b/Makefile b/sdk/src/zx7b/Makefile index 8799501..823104c 100644 --- a/sdk/src/zx7b/Makefile +++ b/sdk/src/zx7b/Makefile @@ -30,7 +30,9 @@ bindir ?= $(exec_prefix)/bin INSTALL ?= install INSTALL_PROGRAM ?= $(INSTALL) -BINS = zx7b$(EXESUFFIX) +BINS=\ + zx7b$(EXESUFFIX)\ + dzx7b$(EXESUFFIX) .PHONY: all all: $(foreach t,$(BINS),build/$(t)) @@ -42,12 +44,18 @@ $(DESTDIR)$(bindir): build/zx7b$(EXESUFFIX): $(srcdir)/zx7b.c Makefile | build $(CC) $(CFLAGS) -o $@ $< +build/dzx7b$(EXESUFFIX): $(srcdir)/dzx7b.c Makefile | build + $(CC) $(CFLAGS) -o $@ $< + .PHONY: install install: $(foreach t,$(BINS),$(DESTDIR)$(bindir)/$(t)) $(DESTDIR)$(bindir)/zx7b$(EXESUFFIX): build/zx7b$(EXESUFFIX) | $(DESTDIR)$(bindir) $(INSTALL_PROGRAM) $< $@ +$(DESTDIR)$(bindir)/dzx7b$(EXESUFFIX): build/dzx7b$(EXESUFFIX) | $(DESTDIR)$(bindir) + $(INSTALL_PROGRAM) $< $@ + .PHONY: uninstall uninstall: rm -f $(foreach t,$(BINS),$(DESTDIR)$(bindir)/$(t)) diff --git a/sdk/src/zx7b/dzx7b.c b/sdk/src/zx7b/dzx7b.c new file mode 100644 index 0000000..11fd4e6 --- /dev/null +++ b/sdk/src/zx7b/dzx7b.c @@ -0,0 +1,291 @@ +/* + * dzx7b - LZ77/LZSS backwards decompressor. + * + * Copyright (c) 2015 Einar Saukas. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The name of its author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * SPDX-FileCopyrightText: Copyright (c) 2015 Einar Saukas. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * SPDX-LicenseComments: License's text equals to one from https://directory.fsf.org/wiki/License:BSD-3-Clause + */ + +#include +#include +#include + +#define PROGRAM "dzx7b" +#define DESCRIPTION "LZ77/LZSS backwards decompressor." +#define VERSION "1.0 (2015)" +#define COPYRIGHT "Copyright (c) 2015 Einar Saukas. All rights reserved." +#define LICENSE "Distributed under BSD 3-clause license." +#define HOMEPAGE "https://github.com/antoniovillena/zx7b/" + +FILE *ifp; +FILE *ofp; +char *input_name; +char *output_name; +unsigned char *input_data; +unsigned char *output_data; +size_t input_index; +size_t output_index; +size_t input_size; +size_t output_size; +size_t partial_counter; +size_t total_counter; +int bit_mask; +int bit_value; + +int read_byte() { + return input_data[input_index++]; +} + +int read_bit() { + bit_mask >>= 1; + if (bit_mask == 0) { + bit_mask = 128; + bit_value = read_byte(); + } + return bit_value & bit_mask ? 1 : 0; +} + +int read_elias_gamma() { + int i; + int value; + + value = 1; + while (!read_bit()) { + value = value << 1 | read_bit(); + } + if( (value&255)==255 ) + value= -1; + return value; +} + +int read_offset() { + int value; + int i; + + value = read_byte(); + if (value < 128) { + return value; + } else { + i = read_bit(); + i = i << 1 | read_bit(); + i = i << 1 | read_bit(); + i = i << 1 | read_bit(); + return (value & 127 | i << 7) + 128; + } +} + +void write_byte(int value) { + output_data[output_index++] = value; +} + +void write_bytes(int offset, int length) { + if (offset > output_size+output_index) { + fprintf(stderr, "Error: Invalid data in input file %s\n", input_name); + exit(1); + } + while (length-- > 0) { + write_byte(output_data[output_index-offset]); + } +} + +void decompress() { + int length,i; + + input_index = 0; + partial_counter = 0; + output_index = 0; + bit_mask = 0; + + write_byte(read_byte()); + while (1) { + if (!read_bit()) { + write_byte(read_byte()); + } else { + length = read_elias_gamma()+1; + if (length == 0) { + return; + } + write_bytes(read_offset()+1, length); + } + } +} + +void show_help() { + printf( + PROGRAM " version " VERSION " - " DESCRIPTION "\n" + COPYRIGHT "\n" + LICENSE "\n" + "Home page: " HOMEPAGE "\n" + "\n" + "Usage:\n" + " " PROGRAM " [-f] input.zx7 [output]\n" + "\n" + " -f Force overwrite of output file\n" + " output Decompressed output file\n" + ); +} + +int main(int argc, char *argv[]) { + int forced_mode = 0; + int i; + + /* process hidden optional parameters */ + for (i = 1; i < argc && *argv[i] == '-'; i++) { + if (!strcmp(argv[i], "-f")) { + forced_mode = 1; + } else { + fprintf(stderr, "Error: Invalid parameter `%s\'\n", argv[i]); + exit(1); + } + } + + /* determine output filename */ + if (argc == i+1) { + input_name = argv[i]; + input_size = strlen(input_name); + if (input_size > 4 && !strcmp(input_name+input_size-4, ".zx7")) { + output_name = (char *)malloc(input_size); + strcpy(output_name, input_name); + output_name[input_size-4] = '\0'; + } else { + fprintf(stderr, "Error: Cannot infer output filename\n"); + exit(1); + } + } else if (argc == i+2) { + input_name = argv[i]; + output_name = argv[i+1]; + } else { + show_help(); + exit(1); + } + + /* open input file */ + ifp = fopen(input_name, "rb"); + if (!ifp) { + fprintf(stderr, "Error: Cannot access input file %s\n", input_name); + exit(1); + } + + /* determine input size */ + fseek(ifp, 0L, SEEK_END); + input_size = ftell(ifp); + fseek(ifp, 0L, SEEK_SET); + if (!input_size) { + fprintf(stderr, "Error: Empty input file %s\n", argv[1]); + exit(1); + } + + /* allocate input buffer */ + input_data = (unsigned char *)malloc(input_size); + if (!input_data) { + fprintf(stderr, "Error: Insufficient memory\n"); + exit(1); + } + + /* read input file */ + total_counter = 0; + do { + partial_counter = fread(input_data+total_counter, sizeof(char), input_size-total_counter, ifp); + total_counter += partial_counter; + } while ( partial_counter > 0 ); + + if (total_counter != input_size) { + fprintf(stderr, "Error: Cannot read input file %s\n", argv[1]); + exit(1); + } + + /* check output file */ + if (!forced_mode && fopen(output_name, "rb") != NULL) { + fprintf(stderr, "Error: Already existing output file %s\n", output_name); + exit(1); + } + + /* create output file */ + ofp = fopen(output_name, "wb"); + if (!ofp) { + fprintf(stderr, "Error: Cannot create output file %s\n", output_name); + exit(1); + } + + /* reverse input data */ + for ( i= 0; i>1; i++ ){ + partial_counter = input_data[i]; + input_data[i] = input_data[input_size-1-i]; + input_data[input_size-1-i] = partial_counter; + } + + /* calculate output file size and allocate memory */ + output_size = 1; + read_byte(); + while (1) { + if (!read_bit()) { + output_size++; + read_byte(); + } else { + i = read_elias_gamma()+1; + if (i == 0) { + break; + } + read_offset(); + output_size+= i; + } + } + output_data = (unsigned char *)malloc(output_size); + if (!output_data) { + fprintf(stderr, "Error: Insufficient memory\n"); + exit(1); + } + + /* decompress */ + decompress(); + + /* reverse output data */ + for ( i= 0; i>1; i++ ) { + partial_counter= output_data[i]; + output_data[i]= output_data[output_size-1-i]; + output_data[output_size-1-i]= partial_counter; + } + + /* write output file */ + if (fwrite(output_data, sizeof(char), output_size, ofp) != output_size) { + fprintf(stderr, "Error: Cannot write output file %s\n", output_name); + exit(1); + } + + /* close input file */ + fclose(ifp); + + /* close output file */ + fclose(ofp); + + /* done! */ + printf("File `%s' converted from %lu to %lu bytes!\n", + output_name, (unsigned long)input_size, (unsigned long)output_size); + + return 0; +} diff --git a/utils/README.md b/utils/README.md index d560636..63a865e 100644 --- a/utils/README.md +++ b/utils/README.md @@ -40,6 +40,7 @@ Files: * `UPGRADE` * `UPGRZX2` * `UPGRZXD` +* `ZXUNOCFG` ## Build utilities