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
+}