Reference manual · CBS Cruncher v5.5

From dropped file
to working Z80 code.

This guide explains what the browser actually stores, how each output route reconstructs the data, which decruncher to use, and where the current limits are. Start with the practical path, then use the byte reference when integrating the decoder into a game.

01 · Quick start

Use the shortest path that matches the asset

  1. Drop the source.BIN, PSG and other arbitrary files enter as continuous bytes. BMP, PNG and SC5–SC8 files enter as native image pixels.
  2. Check the interpretation.For images, verify Screen mode, packed bytes per line and line count. For raw BIN input, geometry must exactly match the data size.
  3. Select compressors.Recommended runs the active formats. Select all also measures the slower v4.3 historical comparison.
  4. Run and choose a result.Every candidate is browser-decrunched and compared byte-for-byte before it is offered.
  5. Download data and code.Choose RAM, RAM-tail, buffered VRAM, linear VRAM or direct VRAM, then use the matching generated or reference source.
Already have a .CB5 file?

Drop it on the compressor. The page automatically switches to decrunch mode and verifies the recovered bytes locally.

02 · Input and interpretation

The file type and the data model are separate choices

Continuous data treats every byte as part of one stream. Use it for code, maps, text, sound, Screens 1–4 data and any image whose rows should be joined without a rectangle rule. Image modes preserve row geometry so v5.5 can test whole-line offsets and the generated decoder can write an exact rectangle.

ModePixel formatNormal packed widthUse
Screen 54-bit palette · 2 pixels/byte128 bytes256-pixel images
Screen 62-bit palette · 4 pixels/byte128 bytes512-pixel images
Screen 74-bit palette · 2 pixels/byte256 bytes512-pixel images
Screen 88-bit direct colour · 1 pixel/byte256 bytes256-pixel images

Native BMP/PNG import removes the file header, palette records and row padding, then converts pixels to the selected MSX packing. A valid seven-byte BSAVE header in SC5–SC8 is detected and removed. Changing Screen 5/7 after importing an image does not silently change the imported packed width.

03 · Reading the result

Smallest verified file wins—within the selected routes

SIZE

Includes the CBS header

The displayed and downloaded size is the complete packed file, not payload only.

VERIFIED

Round-trip proof

The JavaScript decoder reconstructs the source and compares every byte before a result can win.

BUFFER / DIRECT

Same image payload

For a paired image result, only destination bits change. Recompression is not required.

V4.3

Measured baseline

The proven older aligned-cost engine remains available for comparison and legacy integration.

Tiny inputs may grow.

The three-byte v5 header plus token and EOS bits can exceed a very small uncompressed file. The result table reports the real total.

04 · Header and format IDs

One byte selects format, variant and destination

FF VVV DDDFF format familyVVV codec variantDDD destination

Linear files use bytes 1–2 for the complete packed-file length in little-endian order. Image destinations 3 and 5 instead use byte 1 for packed NX and byte 2 for NY; zero represents 256. CBS v4.3 is separate and keeps its established 24-byte CB5 container.

HeaderMeaningDestinationNotes
00h / 80hv5.2 compact pairRAMTwo CBS offset representations
01h / 81hv5.2 compact pairRAM-tailSame payload, safe relocation route
40h / 48hv5.3 / v5.4RAMCombined state-flow decoder
41h / 49hv5.3 / v5.4RAM-tailMeasured in-place tail route
42h / 4Ahv5.3 / v5.4Linear VRAMTiles, fonts and screen streams
43h / 4Bhv5.3 / v5.4 imageBuffered VRAMRAM stage, then HMMC
45h / 4Dhv5.3 / v5.4 imageDirect VRAMCPU, HMMM and HMMV backend
C3h / C5hv5.5 line-awareBuffer / directIdentical payload after byte 0
Source location is not in the packed header.

The selected/generated decoder supplies the reader for RAM, plain ROM or one cartridge mapper. This keeps every data file smaller and avoids carrying unused mapper choices in a game.

05 · Token grammar

Literals establish bytes; matches repeat history

A v5.3/v5.4 stream begins with an interlaced-gamma literal length, followed by those literal bytes. After a literal, one control bit selects a previous-offset match (0) or a new offset (1). After a match, 0 returns to literals and 1 selects another new offset. A previous-offset match saves the complete offset code.

LITERAL

gamma length + raw bytes

LAST OFFSET

gamma match length; reuse the saved negative distance

NEW OFFSET

distance representation + first match-length control bit

Interlaced gamma value

value = 1
while GET_BIT() == 0:
    value = (value << 1) | GET_BIT()
return value

The general distance stores a complemented negative offset. For a positive look-back distance d:

high      = floor((d - 1) / 128) + 1
low       = (d - 1) % 128
packedLow = (127 - low) << 1 | firstLengthControlBit

v5.3 reserves general offset-high 256 as EOS. v5.4 adds one selector before every new distance: 0 codes near distance 1–15, while 1 uses the complete general representation. v5.5 uses its selector for a whole-line distance or the general compact representation.

06 · Worked byte example

Sixty bytes become eleven

The verified v5.4 result for ABC repeated twenty times is:

48 0B 00 71 41 42 43 50 3A AA AC

48headerv5.4 adaptive-near, linear RAM destination

0B 00packed length11 bytes total, little endian

logical token 1literal 3raw bytes 41h 42h 43h = “ABC”

logical token 2new distance 3copy 57 bytes from the already reconstructed ABC sequence

finishEOSthe impossible general offset-high value ends the stream

Control bits, literal bytes and offset data share the payload, so the remaining hex bytes do not each correspond to one complete token. The logical sequence is the reliable way to read it.

07 · Destination routes

The low three bits say what the decoder must do

0

Linear RAM

Normal forward reconstruction.

1

RAM-tail

Relocate packed bytes to the destination tail, then expand.

2

Linear VRAM

Continuous VDP memory using the current Screen physical width.

3

Buffered image

Expand into RAM, then upload an exact NX × NY rectangle.

4

Hybrid

Reserved for a proven row/chunk backend.

5

Direct image

Reconstruct with CPU writes and VDP commands.

6

Mapped RAM

Planned MSX Memory Mapper destination.

08 · RAM integration

Normal output or measured destination-tail reuse

The combined v5.3/v5.4 RAM decoder accepts the complete three-byte header at HL:

    LD      HL,PACKED_DATA
    LD      DE,OUTPUT_BUFFER
    CALL    CBS_V5354_RAM_TO_RAM

v5.2 uses CBS_V52_RAM_TO_RAM. CBS v4.3 has its own compatible source because its container and token grammar predate v5.

Generic RAM-tail entry

    LD      HL,PACKED_DATA
    LD      DE,OUTPUT_BLOCK
    LD      BC,UNPACKED_SIZE
    CALL    CBS_V5354_RAM_TAIL

The generated per-file wrapper stores the unpacked size as CBS_FILE_RAM_TAIL, so a game normally supplies only HL and DE. The routine copies the packed file backward with LDDR to the end of the destination block, then performs the usual forward expansion.

Safety is calculated, not assumed.

The compressor checks every write position against unread packed input. An unsafe file is never offered as a tail build. This is the corrected replacement for the old four-byte-margin assumption.

This is useful when a title screen can temporarily reuse map RAM, or when packed bytes are copied to the end of a buffer before the original content is needed. The compact decoders intentionally do not carry corrupt-stream bounds checks; use them for trusted game-built assets.

09 · Screen 5–8 and VRAM

One public interface, several delivery backends

The generated image binary exposes three stable entry points:

E000hCBS_INIT_MSX

Detect and patch the real MSX VDP ports.

E003hCBS_INIT_SCREEN

Supply Screen mode 5, 6, 7 or 8.

E006hCBS_DECRUNCH

Decode the selected buffer, linear or direct route.

    CALL    CBS_INIT_MSX

    LD      A,7
    CALL    CBS_INIT_SCREEN

    LD      HL,PACKED_IMAGE
    LD      DE,(PACKED_X << 8) | Y
    LD      A,VRAM_PAGE << 2
    CALL    CBS_DECRUNCH

For image routes, D is the packed X byte and E is Y, making DE = XY. A bits 3–2 select the VRAM page. HL points to the three-byte CBS header. IX is required only by the buffered route and points to its RAM stage.

BUFFERED · DDD=3

RAM stage + HMMC

Expand the complete image in RAM, then upload the exact packed width × height rectangle. The exact byte count ends HMMC naturally.

DIRECT · DDD=5

v5.3/v5.4/v5.5 direct VRAM

Literals use the CPU VRAM port, matches of one to eight bytes use a dedicated RAM buffer, longer matches use HMMM, and long offset-one runs use HMMV.

LINEAR · DDD=2

Tiles and fonts

Write a continuous stream while respecting the physical Screen line width; no NX × NY rectangle is required.

COMMAND RULE

Wait only when needed

VDP-to-VDP commands must finish before the next command. CPU data may be sent through the normal VRAM port while a different command area is active.

Which delivery route should I use?

SituationRecommended routeReasonDecoder
Large image or little free RAMDirect VRAMNo complete expanded image buffer; v5.5 can retain whole-line matches.direct
Reusable RAM area is availableBuffered VRAMSimple RAM expansion followed by one exact HMMC rectangle.buffered
Tiles, fonts or linear screen bytesLinear VRAMContinuous output follows the physical Screen width without rectangle geometry.direct
Mapped game mixes both image routesChoose per imageOne mapper-specific decoder dispatches from each file's destination bits.mixed
Recommended default for mapped games

Generate the mixed decoder for the game's one cartridge mapper, then choose Buffer or Direct independently for every image. Use the standalone direct decoder when the project never needs destination 3; it avoids carrying the buffered backend.

Initialize the VDP interface once

After copying the decoder into writable RAM, call CBS_INIT_MSX once before displaying the first image. It reads the BIOS VDP data-port values from 0006h and 0007h, then patches every immediate CPU-transfer, status and indirect-command port operand. The same decoder therefore works when a machine's VDP ports differ from the standard 98h9Bh addresses.

The direct backend uses a dedicated eight-byte RAM buffer for non-overlapping matches of one to eight bytes. Larger matches use HMMM, while long offset-one runs may use HMMV. This buffer is decoder working memory; it does not require another initialization. Call CBS_INIT_SCREEN initially and again whenever the Screen mode changes.

Direct matches are divided at destination-row boundaries, source-row boundaries and overlap limits. The one-to-eight-byte scratch threshold and the 64-byte fast-fill threshold belong to the decoder, not the packed format, so they can be tuned without recompressing the image. A size-focused build restricted to the standard VDP ports may hard-code them and omit CBS_INIT_MSX; the supplied source retains portable initialization.

10 · Cartridge ROM input

One mapped decoder handles buffered and direct images

The Screen 5–8 generator compiles exactly one reader for ASCII8, ASCII16, ASCII16-X, Konami or Konami SCC. The game supplies HL as the exact address in the mapper window and BC as the initial bank. The reader detects the active window, patches its fast path and advances banks whenever HL reaches the boundary.

The caller does not split the packed stream.

A file may cross consecutive ROM banks. The generated reader makes that transition while the token decoder continues normally.

The website demonstration keeps page 0 for startup and code, starts packed assets on page 1 by default, runs the decoder at E000h and mapper control at F500h, and leaves 8000h–DFFFh as a 24 KB buffer. Its multi-screen ROM and export table are visualization tools; the CLI intentionally generates only one-image test ROMs. In a mixed ROM, destination 3 expands into the shared 8000h–DFFFh stage and uploads with HMMC; destination 5 reconstructs directly in VRAM. The same E000h/E003h/E006h decoder entries dispatch both routes. For a fair visual comparison, the demo controller sets the border and backdrop to the darkest available palette colour and clears the complete Screen 5–8 VRAM page with HMMV before each image. It waits for the command to finish while restoring status register 0 between CE checks, allowing normal MSX interrupts, and holds the completed black clear for one video frame before starting the decoder. Buffered output appears only after RAM expansion; direct output can be watched as it is reconstructed in VRAM. The harness also disables sprites after each Screen-mode initialization. This prevents stale sprite attributes from appearing over test images and leaves more VDP time available to the decoder.

Do not confuse two kinds of mapper.

Cartridge ROM mapper input is implemented for buffered and direct Screen 5–8 output. Output into selected MSX Memory Mapper RAM segments is still planned.

11 · Python command line

The website engine without the browser UI

Requirements: Python 3.10+, Node.js 22+, and Pillow only when importing BMP/PNG.

# Recommended continuous-data compressors
python cbs_cruncher.py game.bin

# Include every comparison, including v4.3
python cbs_cruncher.py game.bin --compressors all

# Build a measured RAM-tail result
python cbs_cruncher.py game.bin --ram-tail

# Screen 7 image and a one-image test ROM
python cbs_cruncher.py picture.png --mode 7 --rom

# Linear Screen 5 VRAM data
python cbs_cruncher.py tiles.bin --linear-vram-screen 5 --rom

# Decrunch an existing CB5 file
python cbs_cruncher.py packed.cb5 --decompress

Run python cbs_cruncher.py --help for the exact mapper, geometry, search-window and output switches in the current package.

12 · Troubleshooting

Most failures are geometry, route or host limits

DX/DY does not match

For raw BIN input, packed bytes per line × line count must equal the file length. A seven-byte SC5–SC8 BSAVE header is removed only when valid.

Compression appears stuck

Large image searches are expensive. Use the recommended 2 KB window first; the progress bar shows the current engine and measured work.

Testing a long mapper ROM

Use the local WebMSX button. CBS Cruncher opens a dedicated player tab and transfers the full ROM through browser memory, so 128 KB cartridges do not enter the address bar and are never uploaded. The player selects Japanese MSX2 NTSC and applies the chosen mapper format automatically.

RAM-tail is unavailable

The exact overlap trial found that unread packed bytes would be overwritten. Use normal RAM output or a different destination block.

Colours look wrong

Use imported palette data where available and test with the Japanese MSX2 NTSC machine; regional default palettes can differ.

A modified CB5 crashes

The small game decrunchers trust their input and omit defensive bounds checks. Verify files with the browser or CLI before placing them in ROM.

13 · Planned work

Finish missing delivery paths only when they solve a real asset

  1. MSX Memory Mapper RAM output.Define the destination-6 contract, selected segment/window parameters and safe crossing between RAM segments.
  2. Cartridge-ROM to ordinary RAM.The mixed Screen 5–8 reader is complete; a future compact-data route may reuse it for code, maps or other linear RAM destinations.
  3. Optional hybrid image path.Destination 4 remains reserved for row/chunk history or another mixed strategy only if measured game data justifies its code.
  4. More game validation.Continue code-size and speed tuning against real maps, tiles, fonts and Screen 5–8 assets without changing verified payloads unnecessarily.
Reserved does not mean promised.

CBS v5 keeps spare destination and variant values so experiments do not force another container redesign. Only implemented routes are shown as downloadable winners.

14 · Downloads

Use the smallest source set your game needs