diff --git a/Doc/ChangeLog.txt b/Doc/ChangeLog.txt index c4932518..7b57f23b 100644 --- a/Doc/ChangeLog.txt +++ b/Doc/ChangeLog.txt @@ -33,6 +33,7 @@ Version 3.6 - HJB: Added loader for MSX - HJB: Added IDE driver master media detect option - WBW: Add support for S100 Serial I/O DLP Serial connection +- P?D: Generate compressed ROM for EaZyZ80 512 Version 3.5.1 ------------- diff --git a/Source/Clean.cmd b/Source/Clean.cmd index ec661f7c..24229309 100644 --- a/Source/Clean.cmd +++ b/Source/Clean.cmd @@ -27,3 +27,4 @@ pushd ZRC && call Clean & popd pushd Z1RCC && call Clean & popd pushd ZZRCC && call Clean & popd pushd MSX && call Clean & popd +pushd EZ512 && call Clean & popd diff --git a/Source/EZ512/Build.cmd b/Source/EZ512/Build.cmd index 341333e8..a56bdb7c 100644 --- a/Source/EZ512/Build.cmd +++ b/Source/EZ512/Build.cmd @@ -3,9 +3,13 @@ setlocal set TOOLS=../../Tools -set PATH=%TOOLS%\srecord;%PATH% +set PATH=%TOOLS%\zxcc;%TOOLS%\srecord;%TOOLS%\compress;%PATH% -for %%f in (..\..\Binary\RCZ80_ez512_*.rom) do call :build %%~nf +set CPMDIR80=%TOOLS%/cpm/ + +zxcc z80asm -decomp/HL + +for %%f in (..\..\Binary\RCZ80_ez512_*.upd) do call :build %%~nf goto :eof @@ -23,4 +27,8 @@ move temp.dat ..\..\Binary\%1_hd1k_prefix.dat copy /b ..\..\Binary\%1_hd1k_prefix.dat + ..\..\Binary\hd1k_cpm22.img + ..\..\Binary\hd1k_zsdos.img + ..\..\Binary\hd1k_nzcom.img + ..\..\Binary\hd1k_cpm3.img + ..\..\Binary\hd1k_zpm3.img + ..\..\Binary\hd1k_ws4.img ..\..\Binary\%1_hd1k_combo.img || exit /b +srec_cat ..\..\Binary\%1.upd -binary -exclude 0x13700 0x14A00 -fill 0xC9 0x13700 0x14A00 -o temp.upd -binary +compress temp.upd +srec_cat decomp.hex -intel temp.upd.cmp -binary -offset 3 -o ..\..\Binary\%1_64k.rom -binary + goto :eof diff --git a/Source/EZ512/Clean.cmd b/Source/EZ512/Clean.cmd index fa12c5c7..8e903c78 100644 --- a/Source/EZ512/Clean.cmd +++ b/Source/EZ512/Clean.cmd @@ -1,3 +1,7 @@ @echo off setlocal +if exist *.upd del *.upd +if exist *.cmp del *.cmp +if exist *.hex del *.hex +if exist *.lst del *.lst diff --git a/Source/EZ512/Makefile b/Source/EZ512/Makefile index cf738f03..9eb3e1e6 100644 --- a/Source/EZ512/Makefile +++ b/Source/EZ512/Makefile @@ -1,13 +1,15 @@ DEST=../../Binary +OTHERS=*.hex *.upd *.cmp HD1KIMGS = $(DEST)/hd1k_cpm22.img $(DEST)/hd1k_zsdos.img $(DEST)/hd1k_nzcom.img \ $(DEST)/hd1k_cpm3.img $(DEST)/hd1k_zpm3.img $(DEST)/hd1k_ws4.img -ROMS := $(wildcard $(DEST)/RCZ80_ez512_*.rom) -ROMS := $(patsubst $(DEST)/%.rom,%,$(ROMS)) +ROMS := $(wildcard $(DEST)/RCZ80_ez512_*.upd) +ROMS := $(patsubst $(DEST)/%.upd,%,$(ROMS)) OBJECTS := $(patsubst %,%_hd1k_prefix.dat,$(ROMS)) OBJECTS += $(patsubst %,%_hd1k_combo.img,$(ROMS)) +OBJECTS += $(patsubst %,%_64k.rom,$(ROMS)) TOOLS = ../../Tools @@ -25,3 +27,8 @@ DIFFPATH = $(DIFFTO)/Binary %_hd1k_combo.img: %_hd1k_prefix.dat $(HD1KIMGS) cat $^ > $@ + +%_64k.rom: $(DEST)/%.upd decomp.hex + srec_cat $< -binary -exclude 0x13700 0x14A00 -fill 0xC9 0x13700 0x14A00 -o temp.upd -binary + $(COMPRESS) temp.upd + srec_cat decomp.hex -intel temp.upd.cmp -binary -offset 3 -o $@ -binary diff --git a/Source/EZ512/decomp.z80 b/Source/EZ512/decomp.z80 new file mode 100644 index 00000000..17c741d6 --- /dev/null +++ b/Source/EZ512/decomp.z80 @@ -0,0 +1,151 @@ +; 251003 decomp_rom_v1.1 +; Mark Pruden: Fix for omitted Bank 4 +; +; 250208 decomp_rom v1.0 +; Paul de Bak: Renamed and used in RomWBW utility program 'compress_upd.c' +; to compress *.upd binary files +; +;1/17/25 +;decompress RomWBW v1.0 - Original version by Bill Shen +;Routine in ROM that decompress RomWBW data file into RAM and jump to it. +;copy data file to RAM starting from bank 0, addr 0. +;when encountered two consecutive bytes of same values, the tird byte following the consecutive values +; describe how many more identical bytes need to be added. +;decompression ends when 3 banks (96KB) are expanded +;compressed data is stored from address $3 to below $FF00 +;decompress program is located at $FF00 + +;register usage +;regC points to bankreg +;regB is ROM source ($20) +;regD is RAM destination bank +;regE is previous value +;regHL is destination pointer +;regIX is source pointer +;regIY points to byte count + +bankreg equ 0ch ;PIO port C is 512K RAM bank register +SIOAData equ 8h ;location of SIO chan A data +SIOACmd equ 9h ;location of SIO ch A command/status reg +SIOBData equ 0ah ;location of SIO chan B data +SIOBCmd equ 0bh ;location of SIO ch B command/status reg +PORTCData equ 0ch ;PIA port C data +PORTCCmd equ 0dh ;PIA port C command + + org 0 + jp 0ff00h ;do program at top of memory +dataRomWBW: +;compressed RomWBW data appended here + org 0ff00h + ld a,09h ;write to KIO command reg first, enable PIA mux + out (0eh),a ; SIO-CTC-PIO priority daisy chain + + ld hl,0ff00h ;copy self into RAM + ld de,0ff00h + ld bc,100h + ldir + + xor a ;PortC are all outputs. This will cause both RAM and ROM + out (PORTCCmd),a ; to be enabled until following OUT instruction, since RAM and + ; ROM have same contents, this won't cause contention + ld a,00100010b ; ROM enable, RAM disable, bank$2, nRTSA, nRTSB enabled + out (PORTCData),a +;register usage +;regC points to bankreg +;regB is ROM source ($20) +;regD is RAM destination bank +;regE is previous value +;regHL is destination pointer +;regIX is source pointer +;regIY points to byte count + ld c,bankreg ;regC points to bank register IO address + ld e,0 ;make sure regE is not the same as very first byte which is 0xC3 + ld b,20h ;regB is ROM source + ld d,80h ;regD is RAM destination + ld hl,0 ;destination starts from bank 0, address 0 + ld ix,dataRomWBW ;regIX points to compressed RomWBW + ld iy,cSame ;regIY points to the count of same value +start: + out (c),b ;read data from ROM +;these two lines are executing program in ROM which has same program as RAM + ld a,(ix) ;read from source + out (c),d +;running in RAM + ld (hl),a ;write to destination + cp e ;two consecutive same values? + jp z,decomp + ld e,a ;update the 'previous' value + inc ix ;next value in ROM + inc hl ;next destination value + ld a,h + cp 80h ;check for address greater than 32KB + jp z,nxtDbank + jp start +nxtDbank: + ld hl,0 + inc d ;next bank + ld a,d +;; cp 83h ;compare to bank 3 + cp 84h ;MP compare to bank 4 + jp z,decompDone + jp start +decomp: + out (c),b ;read data from ROM +;running in ROM + inc ix ;point to byte count of same value + ld a,(ix) ;get the count value + out (c),d ;switch to RAM bank +;running in RAM + dec a ;reduce by 1 because one byte is already written + ld (iy),a ;store count to cSame pointed by regIY + jp z,DoDecomp2 ;just two consecutive values +DoDecomp: + inc hl ;next destination value + ld a,h + cp 80h + jp z,nxtDbank1 +DoDecomp1: + ld (hl),e ;write previous value (in regE) to destination + dec (iy) + jp nz,DoDecomp +DoDecomp2: +;done with block decompression, get ready to start over + out (c),b +;running in ROM + inc ix ;point to next data in ROM + ld e,(ix) + dec e ;make sure previous value does not match, in case of large + ; block (>256) of same values + out (c),d +;running in RAM + inc hl + ld a,h + cp 80h ;check for address grater than 32KB + jp z,nxtDbank2 + jp start +nxtDbank1: + ld hl,0 + inc d ;next bank + ld a,d + cp 83h ;compare to bank3 + jp z,decompDone + out (c),d ;update bank before continuing + jp DoDecomp1 +nxtDbank2: + ld hl,0 + inc d ;next bank + ld a,d + cp 83h ;compare to bank 3 + jp z,decompDone + jp start +decompDone: +;decompression is done, reaching 96KB of data + ld a,80h ;ROM disable, RAM enable, bank$0, nRTSA, nRTSB enabled + out (c),a + jp 0 ;execute RomWBW + +cSame: db 0 ;count of the same value + + end + + diff --git a/Source/ver.inc b/Source/ver.inc index 2a8d9914..54df491b 100644 --- a/Source/ver.inc +++ b/Source/ver.inc @@ -2,7 +2,7 @@ #DEFINE RMN 6 #DEFINE RUP 0 #DEFINE RTP 0 -#DEFINE BIOSVER "3.6.0-dev.33" +#DEFINE BIOSVER "3.6.0-dev.34" #define rmj RMJ #define rmn RMN #define rup RUP diff --git a/Source/ver.lib b/Source/ver.lib index 3502ac45..bd16ea55 100644 --- a/Source/ver.lib +++ b/Source/ver.lib @@ -3,5 +3,5 @@ rmn equ 6 rup equ 0 rtp equ 0 biosver macro - db "3.6.0-dev.33" + db "3.6.0-dev.34" endm diff --git a/Tools/Makefile.inc b/Tools/Makefile.inc index 1701be38..cde5b3d5 100644 --- a/Tools/Makefile.inc +++ b/Tools/Makefile.inc @@ -45,6 +45,7 @@ OPENSPIN=$(BINDIR)/openspin CPMCP=$(BINDIR)/cpmcp CPMLS=$(BINDIR)/cpmls CPMCHATTR=$(BINDIR)/cpmchattr +COMPRESS=$(BINDIR)/compress # # directory containing cpm binaries diff --git a/Tools/compress/compress.exe b/Tools/compress/compress.exe new file mode 100644 index 00000000..7643b806 Binary files /dev/null and b/Tools/compress/compress.exe differ diff --git a/Tools/unix/Makefile b/Tools/unix/Makefile index 7cefdb27..49342c90 100644 --- a/Tools/unix/Makefile +++ b/Tools/unix/Makefile @@ -13,7 +13,7 @@ ifeq ($(UNAME), Darwin) SUFFIX=osx endif -SUBDIRS = OpenSpin uz80as zxcc cpmtools bin2asm lzsa +SUBDIRS = OpenSpin uz80as zxcc cpmtools bin2asm lzsa compress all: @chmod +x casefn.sh diff --git a/Tools/unix/compress/Makefile b/Tools/unix/compress/Makefile new file mode 100644 index 00000000..c59580cc --- /dev/null +++ b/Tools/unix/compress/Makefile @@ -0,0 +1,12 @@ +APP := compress +OBJS := compress.o +UNAME := $(shell uname) + +all: $(APP) + cp -p $(APP) ../../$(UNAME) + +$(APP): $(OBJS) + $(CC) $^ -o $@ + +clean: + @rm -rf $(APP) $(OBJS) diff --git a/Tools/unix/compress/compress.c b/Tools/unix/compress/compress.c new file mode 100644 index 00000000..2292a447 --- /dev/null +++ b/Tools/unix/compress/compress.c @@ -0,0 +1,150 @@ +/* ===================================================================== + * compress v1.1 - 251012 Paul de Bak, with help from Le Chat AI + * + * ===================================================================== + * This RomWBW utility program will attempt to compress any file using + * a straightforward RLE approach. + * + * The output file will have the name of the input file with ".cmp" + * appended. + * + * ===================================================================== + * To compile in Linux (or Windows using MinGW): + * + * gcc -o compress_upd(.exe) compress_upd.c + * + * ===================================================================== + * Usage: compress(.exe) + * + * If compression is successful, an ouput file is created with the name + * of the input file + ".cmp". + * + * ===================================================================== + * Program exit codes + * 0: Success. An output file is created. + * 1: Incorrect usage or input file not found. + * 2: Unable to create output file. + * + * ===================================================================== + */ + +#include +#include +#include +//#include +//#include // For basename function + +#define VERSION "compress v1.1 - 251012 Paul de Bak & Le Chat AI" +#define MAX_COUNT 0x100 // Maximum count is 256 +#define BUFFER_SIZE 65536 + +size_t calculate_original_size(FILE *input) { + fseek(input, 0, SEEK_END); + return ftell(input); +} + +size_t calculate_compressed_size(FILE *input) { + uint8_t buffer[BUFFER_SIZE]; + size_t size, compressed_size = 0; + while ((size = fread(buffer, 1, BUFFER_SIZE, input)) > 0) { + size_t i = 0; + while (i < size) { + uint8_t byte = buffer[i]; + size_t count = 1; + // Count the number of repetitions of the current byte + while (i + count < size && buffer[i + count] == byte && count < MAX_COUNT) { + count++; + } + if (count >= 2) { + compressed_size += 3; // Two bytes + count + } else { + compressed_size += 1; // Single byte + } + i += count; + } + } + return compressed_size; +} + +int compress_file(FILE *input, FILE *output) { + uint8_t buffer[BUFFER_SIZE]; + size_t size; + uint8_t repeat_count; + while ((size = fread(buffer, 1, BUFFER_SIZE, input)) > 0) { + size_t i = 0; + while (i < size) { + uint8_t byte = buffer[i]; + size_t count = 1; + // Count the number of repetitions of the current byte + while (i + count < size && buffer[i + count] == byte && count < MAX_COUNT) { + count++; + } + if (count >= 2) { + fwrite(&byte, 1, 1, output); + fwrite(&byte, 1, 1, output); + repeat_count = count - 1; + fwrite(&repeat_count, 1, 1, output); + } else { + fwrite(&byte, 1, 1, output); + } + i += count; + } + } + return 1; +} + +int main(int argc, char *argv[]) { + char *input_filename; + long free_bytes; + FILE *input; + size_t original_size; + size_t compressed_size; + char output_filename[256]; + char *base_name; + char *dot; + FILE *output; + + printf("\n%s\n\n", VERSION); + + if (argc != 2) { + printf("Usage: %s \n", argv[0]); + printf("Example: %s RCZ80_ez512_std.upd\n", argv[0]); + return 1; // Error: Incorrect usage + } + + input_filename = argv[1]; + input = fopen(input_filename, "rb"); + if (!input) { + fprintf(stderr, "Error: Input file '%s' not found\n", input_filename); + return 1; // Error: Input file not found + } + + // Calculate the original file size + original_size = calculate_original_size(input); + rewind(input); + + // Calculate the compressed size first + compressed_size = calculate_compressed_size(input); + rewind(input); + + // Construct the output filename + snprintf(output_filename, sizeof(output_filename), "%s.cmp", input_filename); + + printf("Compressing %s to %s...\n", input_filename, output_filename); + + output = fopen(output_filename, "wb"); + if (!output) { + fprintf(stderr, "Error: Unable to create output file '%s'\n", output_filename); + fclose(input); + return 2; // Error: Unable to create output file + } + + compress_file(input, output); + + fclose(input); + fclose(output); + + printf("Compressed from %lu bytes to %lu bytes (%lu%% reduction)\n", original_size, compressed_size, (((original_size - compressed_size) * 100) / original_size)); + + return 0; // Success +}