diff --git a/benchmark.png b/benchmark.png index 309ce01..28cb57d 100644 Binary files a/benchmark.png and b/benchmark.png differ diff --git a/benchmark/benchmark-stc0.sms.asm b/benchmark/benchmark-stc0.sms.asm new file mode 100644 index 0000000..aa420fe --- /dev/null +++ b/benchmark/benchmark-stc0.sms.asm @@ -0,0 +1,27 @@ +; { "technology": "Simple Tile Compression 0", "extension": "stc0compr" } + +.memorymap +defaultslot 0 +slotsize $4000 +slot 0 $0000 +.endme + +.rombankmap +bankstotal 1 +banksize $4000 +banks 1 +.endro + +.bank 0 slot 0 + +.org 0 + ld hl,data + ld de,$4000 + call stc0_decompress + ret ; ends the test + +.block "decompressor" +.include "../decompressors/stc0_decomp.asm" +.endb + +data: .incbin "data.stc0compr" diff --git a/compressors/gfxcomp_stc0.cpp b/compressors/gfxcomp_stc0.cpp new file mode 100644 index 0000000..4590cc1 --- /dev/null +++ b/compressors/gfxcomp_stc0.cpp @@ -0,0 +1,123 @@ +#include + +extern "C" __declspec(dllexport) const char* getName() +{ + return "Simple Tile Compressor Zero"; +} + +extern "C" __declspec(dllexport) const char* getExt() +{ + return "stc0compr"; +} + +extern "C" __declspec(dllexport) int compressTiles( + const uint8_t* pSource, + const uint32_t numTiles, + uint8_t* pDestination, + const uint32_t destinationLength) +{ + if (destinationLength < numTiles * 40 + 1) + { + return 0; + } + // please give me more space for the data (up to 40 bytes per tile needed worst case scenario, plus 1 byte terminator) + + uint8_t lastValue = 0; + uint8_t values[4]; + int finalSize = 0; + + for (unsigned int tileNumber = 0; tileNumber < numTiles; tileNumber++) + { + // loop over all tiles + for (unsigned char i = 0; i < 8; i++) + { + // loop over all the 8 rows of the tile + unsigned char mask = 0b00000000; + bool lastValid = false; + unsigned char valuesCount = 0; + + if (pSource[0] == 0x00) + { + mask |= 0b10000000; + } + else if (pSource[0] == 0xFF) + { + mask |= 0b11000000; + } + else + { + mask |= 0b01000000; // raw + lastValid = true; + lastValue = pSource[0]; + values[valuesCount++] = pSource[0]; + } + + if (pSource[1] == 0x00) + { + mask |= 0b00100000; + } + else if (pSource[1] == 0xFF) + { + mask |= 0b00110000; + } + else if (!lastValid || + pSource[1] != lastValue) + { + mask |= 0b00010000; // raw + lastValid = true; + lastValue = pSource[1]; + values[valuesCount++] = pSource[1]; + } + + if (pSource[2] == 0x00) + { + mask |= 0b00001000; + } + else if (pSource[2] == 0xFF) + { + mask |= 0b00001100; + } + else if (!lastValid || + pSource[2] != lastValue) + { + mask |= 0b00000100; // raw + lastValid = true; + lastValue = pSource[2]; + values[valuesCount++] = pSource[2]; + } + + if (pSource[3] == 0x00) + { + mask |= 0b00000010; + } + else if (pSource[3] == 0xFF) + { + mask |= 0b00000011; + } + else if (!lastValid || + pSource[3] != lastValue) + { + mask |= 0b00000001; // raw + lastValid = true; + lastValue = pSource[3]; + values[valuesCount++] = pSource[3]; + } + + *pDestination++ = mask; // write mask byte + + for (unsigned char j = 0; j < valuesCount; j++) + { + *pDestination++ = values[j]; // dump uncompressed values + } + + finalSize += 1 + valuesCount; // add this to finalSize + + pSource += 4; // skip to next 4 bytes + } + } + + *pDestination = 0x00; // end of data + finalSize++; + + return finalSize; // report size to caller +} diff --git a/compressors/gfxcomp_stc0.vcxproj b/compressors/gfxcomp_stc0.vcxproj new file mode 100644 index 0000000..b48ba3d --- /dev/null +++ b/compressors/gfxcomp_stc0.vcxproj @@ -0,0 +1,87 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + {eb4e5423-ca2c-4020-8796-438e218ff0e0} + Win32Proj + 10.0 + + + + DynamicLibrary + v143 + true + + + DynamicLibrary + v143 + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + + + $(SolutionDir)$(Configuration)\$(ProjectName)\ + + + $(SolutionDir)$(Configuration)\$(ProjectName)\ + + + + WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + Level4 + true + Disabled + MultiThreadedDebugDLL + true + + + MachineX86 + false + $(IntermediateOutputPath)$(TargetName).lib + + + + + WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + Level4 + true + true + true + + + true + true + MachineX86 + false + $(IntermediateOutputPath)$(TargetName).lib + Windows + UseFastLinkTimeCodeGeneration + true + + + + + + \ No newline at end of file diff --git a/compressors/tilecompressordlls.sln b/compressors/tilecompressordlls.sln index d91887a..7e3610f 100644 --- a/compressors/tilecompressordlls.sln +++ b/compressors/tilecompressordlls.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30225.117 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32811.315 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gfxcomp_phantasystar", "gfxcomp_phantasystar.vcxproj", "{CDDC9081-7930-454C-A887-B72BDFE9DE93}" EndProject @@ -52,140 +52,102 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .editorconfig = .editorconfig EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gfxcomp_stc0", "gfxcomp_stc0.vcxproj", "{EB4E5423-CA2C-4020-8796-438E218FF0E0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 - Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {CDDC9081-7930-454C-A887-B72BDFE9DE93}.Debug|x64.ActiveCfg = Debug|Win32 {CDDC9081-7930-454C-A887-B72BDFE9DE93}.Debug|x86.ActiveCfg = Debug|Win32 {CDDC9081-7930-454C-A887-B72BDFE9DE93}.Debug|x86.Build.0 = Debug|Win32 - {CDDC9081-7930-454C-A887-B72BDFE9DE93}.Release|x64.ActiveCfg = Release|Win32 {CDDC9081-7930-454C-A887-B72BDFE9DE93}.Release|x86.ActiveCfg = Release|Win32 {CDDC9081-7930-454C-A887-B72BDFE9DE93}.Release|x86.Build.0 = Release|Win32 - {7D600DE4-F899-4BD7-9CFB-C6BFF8A76514}.Debug|x64.ActiveCfg = Debug|Win32 {7D600DE4-F899-4BD7-9CFB-C6BFF8A76514}.Debug|x86.ActiveCfg = Debug|Win32 {7D600DE4-F899-4BD7-9CFB-C6BFF8A76514}.Debug|x86.Build.0 = Debug|Win32 - {7D600DE4-F899-4BD7-9CFB-C6BFF8A76514}.Release|x64.ActiveCfg = Release|Win32 {7D600DE4-F899-4BD7-9CFB-C6BFF8A76514}.Release|x86.ActiveCfg = Release|Win32 {7D600DE4-F899-4BD7-9CFB-C6BFF8A76514}.Release|x86.Build.0 = Release|Win32 - {F318F9F9-9F30-484C-B1EE-3F20FE6CC480}.Debug|x64.ActiveCfg = Debug|Win32 {F318F9F9-9F30-484C-B1EE-3F20FE6CC480}.Debug|x86.ActiveCfg = Debug|Win32 {F318F9F9-9F30-484C-B1EE-3F20FE6CC480}.Debug|x86.Build.0 = Debug|Win32 - {F318F9F9-9F30-484C-B1EE-3F20FE6CC480}.Release|x64.ActiveCfg = Release|Win32 {F318F9F9-9F30-484C-B1EE-3F20FE6CC480}.Release|x86.ActiveCfg = Release|Win32 {F318F9F9-9F30-484C-B1EE-3F20FE6CC480}.Release|x86.Build.0 = Release|Win32 - {EEA25CFF-B4E6-4585-AD37-54F2F2A28DFC}.Debug|x64.ActiveCfg = Debug|Win32 {EEA25CFF-B4E6-4585-AD37-54F2F2A28DFC}.Debug|x86.ActiveCfg = Debug|Win32 {EEA25CFF-B4E6-4585-AD37-54F2F2A28DFC}.Debug|x86.Build.0 = Debug|Win32 - {EEA25CFF-B4E6-4585-AD37-54F2F2A28DFC}.Release|x64.ActiveCfg = Release|Win32 {EEA25CFF-B4E6-4585-AD37-54F2F2A28DFC}.Release|x86.ActiveCfg = Release|Win32 {EEA25CFF-B4E6-4585-AD37-54F2F2A28DFC}.Release|x86.Build.0 = Release|Win32 - {279B63D9-4BFE-406C-A6C2-756D3082BB36}.Debug|x64.ActiveCfg = Debug|Win32 {279B63D9-4BFE-406C-A6C2-756D3082BB36}.Debug|x86.ActiveCfg = Debug|Win32 {279B63D9-4BFE-406C-A6C2-756D3082BB36}.Debug|x86.Build.0 = Debug|Win32 - {279B63D9-4BFE-406C-A6C2-756D3082BB36}.Release|x64.ActiveCfg = Release|Win32 {279B63D9-4BFE-406C-A6C2-756D3082BB36}.Release|x86.ActiveCfg = Release|Win32 {279B63D9-4BFE-406C-A6C2-756D3082BB36}.Release|x86.Build.0 = Release|Win32 - {2AAEA610-2056-497A-86F1-F83DCE7682D4}.Debug|x64.ActiveCfg = Debug|Win32 {2AAEA610-2056-497A-86F1-F83DCE7682D4}.Debug|x86.ActiveCfg = Debug|Win32 {2AAEA610-2056-497A-86F1-F83DCE7682D4}.Debug|x86.Build.0 = Debug|Win32 - {2AAEA610-2056-497A-86F1-F83DCE7682D4}.Release|x64.ActiveCfg = Release|Win32 {2AAEA610-2056-497A-86F1-F83DCE7682D4}.Release|x86.ActiveCfg = Release|Win32 {2AAEA610-2056-497A-86F1-F83DCE7682D4}.Release|x86.Build.0 = Release|Win32 - {48A1D906-9AE6-41B0-9454-8158837CDFDC}.Debug|x64.ActiveCfg = Debug|Win32 {48A1D906-9AE6-41B0-9454-8158837CDFDC}.Debug|x86.ActiveCfg = Debug|Win32 {48A1D906-9AE6-41B0-9454-8158837CDFDC}.Debug|x86.Build.0 = Debug|Win32 - {48A1D906-9AE6-41B0-9454-8158837CDFDC}.Release|x64.ActiveCfg = Release|Win32 {48A1D906-9AE6-41B0-9454-8158837CDFDC}.Release|x86.ActiveCfg = Release|Win32 {48A1D906-9AE6-41B0-9454-8158837CDFDC}.Release|x86.Build.0 = Release|Win32 - {2BE15569-75E9-4321-83AF-0225A3603CC2}.Debug|x64.ActiveCfg = Debug|Win32 {2BE15569-75E9-4321-83AF-0225A3603CC2}.Debug|x86.ActiveCfg = Debug|Win32 {2BE15569-75E9-4321-83AF-0225A3603CC2}.Debug|x86.Build.0 = Debug|Win32 - {2BE15569-75E9-4321-83AF-0225A3603CC2}.Release|x64.ActiveCfg = Release|Win32 {2BE15569-75E9-4321-83AF-0225A3603CC2}.Release|x86.ActiveCfg = Release|Win32 {2BE15569-75E9-4321-83AF-0225A3603CC2}.Release|x86.Build.0 = Release|Win32 - {EEA25CFF-B4E6-4585-AD30-54F2F2A28DFC}.Debug|x64.ActiveCfg = Debug|Win32 {EEA25CFF-B4E6-4585-AD30-54F2F2A28DFC}.Debug|x86.ActiveCfg = Debug|Win32 {EEA25CFF-B4E6-4585-AD30-54F2F2A28DFC}.Debug|x86.Build.0 = Debug|Win32 - {EEA25CFF-B4E6-4585-AD30-54F2F2A28DFC}.Release|x64.ActiveCfg = Release|Win32 {EEA25CFF-B4E6-4585-AD30-54F2F2A28DFC}.Release|x86.ActiveCfg = Release|Win32 {EEA25CFF-B4E6-4585-AD30-54F2F2A28DFC}.Release|x86.Build.0 = Release|Win32 - {EEA25CFF-B4E6-4585-AD30-54F2F2A28D0C}.Debug|x64.ActiveCfg = Debug|Win32 {EEA25CFF-B4E6-4585-AD30-54F2F2A28D0C}.Debug|x86.ActiveCfg = Debug|Win32 {EEA25CFF-B4E6-4585-AD30-54F2F2A28D0C}.Debug|x86.Build.0 = Debug|Win32 - {EEA25CFF-B4E6-4585-AD30-54F2F2A28D0C}.Release|x64.ActiveCfg = Release|Win32 {EEA25CFF-B4E6-4585-AD30-54F2F2A28D0C}.Release|x86.ActiveCfg = Release|Win32 {EEA25CFF-B4E6-4585-AD30-54F2F2A28D0C}.Release|x86.Build.0 = Release|Win32 - {B3EFFF2D-80A9-40DB-AB5E-F6564AE924F9}.Debug|x64.ActiveCfg = Debug|Win32 {B3EFFF2D-80A9-40DB-AB5E-F6564AE924F9}.Debug|x86.ActiveCfg = Debug|Win32 {B3EFFF2D-80A9-40DB-AB5E-F6564AE924F9}.Debug|x86.Build.0 = Debug|Win32 - {B3EFFF2D-80A9-40DB-AB5E-F6564AE924F9}.Release|x64.ActiveCfg = Release|Win32 {B3EFFF2D-80A9-40DB-AB5E-F6564AE924F9}.Release|x86.ActiveCfg = Release|Win32 {B3EFFF2D-80A9-40DB-AB5E-F6564AE924F9}.Release|x86.Build.0 = Release|Win32 - {282B8C1C-1687-47B2-9AC5-F4CB1FB1E11F}.Debug|x64.ActiveCfg = Debug|Win32 {282B8C1C-1687-47B2-9AC5-F4CB1FB1E11F}.Debug|x86.ActiveCfg = Debug|Win32 {282B8C1C-1687-47B2-9AC5-F4CB1FB1E11F}.Debug|x86.Build.0 = Debug|Win32 - {282B8C1C-1687-47B2-9AC5-F4CB1FB1E11F}.Release|x64.ActiveCfg = Release|Win32 {282B8C1C-1687-47B2-9AC5-F4CB1FB1E11F}.Release|x86.ActiveCfg = Release|Win32 {282B8C1C-1687-47B2-9AC5-F4CB1FB1E11F}.Release|x86.Build.0 = Release|Win32 - {A936A3A1-2414-4276-B940-3F2358FD3928}.Debug|x64.ActiveCfg = Debug|Win32 {A936A3A1-2414-4276-B940-3F2358FD3928}.Debug|x86.ActiveCfg = Debug|Win32 {A936A3A1-2414-4276-B940-3F2358FD3928}.Debug|x86.Build.0 = Debug|Win32 - {A936A3A1-2414-4276-B940-3F2358FD3928}.Release|x64.ActiveCfg = Release|Win32 {A936A3A1-2414-4276-B940-3F2358FD3928}.Release|x86.ActiveCfg = Release|Win32 {A936A3A1-2414-4276-B940-3F2358FD3928}.Release|x86.Build.0 = Release|Win32 - {CB1429FA-552A-453E-B5A6-8D6CFAE006C6}.Debug|x64.ActiveCfg = Debug|Win32 {CB1429FA-552A-453E-B5A6-8D6CFAE006C6}.Debug|x86.ActiveCfg = Debug|Win32 {CB1429FA-552A-453E-B5A6-8D6CFAE006C6}.Debug|x86.Build.0 = Debug|Win32 - {CB1429FA-552A-453E-B5A6-8D6CFAE006C6}.Release|x64.ActiveCfg = Release|Win32 {CB1429FA-552A-453E-B5A6-8D6CFAE006C6}.Release|x86.ActiveCfg = Release|Win32 {CB1429FA-552A-453E-B5A6-8D6CFAE006C6}.Release|x86.Build.0 = Release|Win32 - {046E0C05-BEDD-484E-882D-BE3FF4531636}.Debug|x64.ActiveCfg = Debug|Win32 {046E0C05-BEDD-484E-882D-BE3FF4531636}.Debug|x86.ActiveCfg = Debug|Win32 {046E0C05-BEDD-484E-882D-BE3FF4531636}.Debug|x86.Build.0 = Debug|Win32 - {046E0C05-BEDD-484E-882D-BE3FF4531636}.Release|x64.ActiveCfg = Release|Win32 {046E0C05-BEDD-484E-882D-BE3FF4531636}.Release|x86.ActiveCfg = Release|Win32 {046E0C05-BEDD-484E-882D-BE3FF4531636}.Release|x86.Build.0 = Release|Win32 - {48A1D906-9AE6-41B0-9454-8158837CDFFF}.Debug|x64.ActiveCfg = Debug|Win32 {48A1D906-9AE6-41B0-9454-8158837CDFFF}.Debug|x86.ActiveCfg = Debug|Win32 {48A1D906-9AE6-41B0-9454-8158837CDFFF}.Debug|x86.Build.0 = Debug|Win32 - {48A1D906-9AE6-41B0-9454-8158837CDFFF}.Release|x64.ActiveCfg = Release|Win32 {48A1D906-9AE6-41B0-9454-8158837CDFFF}.Release|x86.ActiveCfg = Release|Win32 {48A1D906-9AE6-41B0-9454-8158837CDFFF}.Release|x86.Build.0 = Release|Win32 - {48A1D906-9AE6-41B0-9454-DEADBEEFDFFF}.Debug|x64.ActiveCfg = Debug|Win32 {48A1D906-9AE6-41B0-9454-DEADBEEFDFFF}.Debug|x86.ActiveCfg = Debug|Win32 {48A1D906-9AE6-41B0-9454-DEADBEEFDFFF}.Debug|x86.Build.0 = Debug|Win32 - {48A1D906-9AE6-41B0-9454-DEADBEEFDFFF}.Release|x64.ActiveCfg = Release|Win32 {48A1D906-9AE6-41B0-9454-DEADBEEFDFFF}.Release|x86.ActiveCfg = Release|Win32 {48A1D906-9AE6-41B0-9454-DEADBEEFDFFF}.Release|x86.Build.0 = Release|Win32 - {D38ABA01-D125-4C36-8EE1-E3598B3BE477}.Debug|x64.ActiveCfg = Debug|Win32 {D38ABA01-D125-4C36-8EE1-E3598B3BE477}.Debug|x86.ActiveCfg = Debug|Win32 {D38ABA01-D125-4C36-8EE1-E3598B3BE477}.Debug|x86.Build.0 = Debug|Win32 - {D38ABA01-D125-4C36-8EE1-E3598B3BE477}.Release|x64.ActiveCfg = Release|Win32 {D38ABA01-D125-4C36-8EE1-E3598B3BE477}.Release|x86.ActiveCfg = Release|Win32 {D38ABA01-D125-4C36-8EE1-E3598B3BE477}.Release|x86.Build.0 = Release|Win32 - {48A1D906-9AE6-41B0-9454-DEADBEEFDF01}.Debug|x64.ActiveCfg = Debug|Win32 {48A1D906-9AE6-41B0-9454-DEADBEEFDF01}.Debug|x86.ActiveCfg = Debug|Win32 {48A1D906-9AE6-41B0-9454-DEADBEEFDF01}.Debug|x86.Build.0 = Debug|Win32 - {48A1D906-9AE6-41B0-9454-DEADBEEFDF01}.Release|x64.ActiveCfg = Release|Win32 {48A1D906-9AE6-41B0-9454-DEADBEEFDF01}.Release|x86.ActiveCfg = Release|Win32 {48A1D906-9AE6-41B0-9454-DEADBEEFDF01}.Release|x86.Build.0 = Release|Win32 - {FABDF0DC-04BD-487C-9C37-491873A06C8D}.Debug|x64.ActiveCfg = Debug|Win32 {FABDF0DC-04BD-487C-9C37-491873A06C8D}.Debug|x86.ActiveCfg = Debug|Win32 {FABDF0DC-04BD-487C-9C37-491873A06C8D}.Debug|x86.Build.0 = Debug|Win32 - {FABDF0DC-04BD-487C-9C37-491873A06C8D}.Release|x64.ActiveCfg = Release|Win32 {FABDF0DC-04BD-487C-9C37-491873A06C8D}.Release|x86.ActiveCfg = Release|Win32 {FABDF0DC-04BD-487C-9C37-491873A06C8D}.Release|x86.Build.0 = Release|Win32 - {DD14E330-BFA3-4812-A84F-694065654AD6}.Debug|x64.ActiveCfg = Debug|Win32 {DD14E330-BFA3-4812-A84F-694065654AD6}.Debug|x86.ActiveCfg = Debug|Win32 {DD14E330-BFA3-4812-A84F-694065654AD6}.Debug|x86.Build.0 = Debug|Win32 - {DD14E330-BFA3-4812-A84F-694065654AD6}.Release|x64.ActiveCfg = Release|Win32 {DD14E330-BFA3-4812-A84F-694065654AD6}.Release|x86.ActiveCfg = Release|Win32 {DD14E330-BFA3-4812-A84F-694065654AD6}.Release|x86.Build.0 = Release|Win32 + {EB4E5423-CA2C-4020-8796-438E218FF0E0}.Debug|x86.ActiveCfg = Debug|Win32 + {EB4E5423-CA2C-4020-8796-438E218FF0E0}.Debug|x86.Build.0 = Debug|Win32 + {EB4E5423-CA2C-4020-8796-438E218FF0E0}.Release|x86.ActiveCfg = Release|Win32 + {EB4E5423-CA2C-4020-8796-438E218FF0E0}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/decompressors/stc0_decomp.asm b/decompressors/stc0_decomp.asm new file mode 100644 index 0000000..b47abac --- /dev/null +++ b/decompressors/stc0_decomp.asm @@ -0,0 +1,66 @@ +;~ +;~ STC0 simple tile compression zero (uses no RAM) +;~ +;~ one byte holds information on how to create the next 4 bytes, two bits for each: +;~ +;~ D7 D6 D5 D4 D3 D2 D1 D0 +;~ +;~ 1st byte 2nd byte 3rd byte 4th byte +;~ +;~ +;~ 0b10 -> write value 0x00 +;~ 0b11 -> value 0xFF +;~ 0b01 -> uncompressed (data byte follows) +;~ 0b00 -> same uncompressed byte as the previous one (in this set of 4) OR end of stream if this is the first two bits (setting the whole byte to 0x00 works fine as EOD) +;~ + +;~ IN: +;~ HL (data source address) +;~ DE (destination in VRAM w/flags) +;~ clobbers: +;~ AF,BC,DE,HL +;~ + +stc0_decompress: + ld c,$bf ; VDP_CTRL_PORT + di + out (c),e + out (c),d + ei + dec c ; same as ld c,VDP_DATA_PORT_ADDRESS + ld de,$00FF ; D = $00, E = $FF + +_stc0_decompress_outer_loop: + ld b,4 + ld a,(hl) + inc hl + +_stc0_decompress_inner_loop: + rla + jr c,_compressed_byte ; if 1X found, write $00 or $FF + rla + jr nc,_same_byte_or_leave + outi ; write raw byte + jr nz,_stc0_decompress_inner_loop + jp _stc0_decompress_outer_loop + +_same_byte_or_leave: + bit 2,b + ret nz ; 00 found in first 2 bits -> end of data, leave + dec hl + outi ; write same raw byte again + jr nz,_stc0_decompress_inner_loop + jp _stc0_decompress_outer_loop + +_compressed_byte: + rla + jr c,_compressed_FF + out (c),d ; write $00 + djnz _stc0_decompress_inner_loop + jp _stc0_decompress_outer_loop + +_compressed_FF: + out (c),e ; write $FF + djnz _stc0_decompress_inner_loop + jp _stc0_decompress_outer_loop +