Building a Human68k utility to convert BMP images to X68000 format

The Sharp X68000 remains a fascinating machine for retrocomputing enthusiasts, particularly those of us based in Australia who appreciate the Motorola 68000 architecture and the unique software library that never made it westward. While the platform lacks a mainstream image editing ecosystem, the need to transfer modern bitmaps onto genuine hardware persists for game development, demoscene productions, and documentation projects. A custom conversion tool that runs natively on Human68k bridges the gap between contemporary image sources and the X68000's distinctive graphics hardware.

Human68k, the operating system bundled with most X68000 models, provides a straightforward file I/O model that suits batch image processing. However, the 68000 CPU at 10 MHz and the limited memory map of stock configurations mean the utility must be carefully engineered. Source images arrive in BMP format from scanners, modern operating systems, or downloads, but the X68000 expects specific pixel layouts, palette depths, and in some cases tile-based arrangements. Writing a converter that handles these constraints teaches a great deal about the machine's video subsystem.

This guide covers the full pipeline: examining the target formats, configuring a cross-compilation toolchain, parsing BMP files, applying colour reduction, and emitting output that loads cleanly under Human68k. The development notes are written from a distinctly Australian perspective, covering practical issues like sourcing components from local contacts, dealing with the time difference when chasing Japanese auction listings, and managing the climate in a home workshop.

Understanding X68000 native image formats

The X68000 video hardware supports a range of resolutions and colour depths, but the two most relevant targets for a BMP conversion utility are the 16-colour and 256-colour planar modes. The standard 512 KB of VRAM allows 768×512 resolution with 16 colours, or 512×512 with 256 colours. Higher modes such as 16-bit colour or 1024×1024 resolution are available on later models with expanded memory. For this reason, the utility must detect the intended target mode and quantise the source image accordingly.

The most common native container is the PI format used by many games and system tools. PI files store data as 16×16 pixel tiles, with each tile holding a palette index and a 16-colour lookup. This tile-based arrangement maps efficiently to the X68000's sprite and scroll hardware, and it reduces the number of disk operations when loading large images. An alternative is a raw GVRAM dump, which simply writes pixel data in the exact order the video chip expects, requiring no on-the-fly unpacking.

Feature Windows BMP X68000 PI X68000 raw GVRAM
Colour depth 1, 4, 8, 24, 32 bpp 4 bpp (16 colours) 4, 8, or 16 bpp
Palette format 24-bit RGB triples 16-bit RGB (5-5-5) Hardware registers
Pixel order Bottom-up rows Top-down, 16×16 tiles Top-down linear
Compression Optional RLE None None
File structure Header + colour table + data Header + tile array Raw pixel stream
Typical use Source images Game assets, demos Display snapshots

The X68000 palette is particularly important. Each of the 16 or 256 colours is stored as a 16-bit value with a 5-bit red, 5-bit green, and 5-bit blue layout, plus a special bit for transparency in some modes. A BMP converter must perform the bit-shifting and remapping from the standard 24-bit BMP palette to this compact representation. For 256-colour targets, the palette extends to 16 bits per channel in some configurations, requiring additional care during the colour table pass.

Setting up a cross-compilation toolchain

Developing a Human68k utility in 2024 almost certainly means cross-compiling on a modern Linux or Windows machine and then testing the output in an emulator or on real hardware. The standard toolchain consists of GCC configured for the m68k-elf target, or the older C68 compiler that produces Human68k-compatible binaries directly. A typical setup involves a shared drive on the development PC and an X68000 emulator running on the same machine, allowing rapid iteration.

Memory layout matters more than it would on a modern desktop. The default X68000 configuration has 2 MB of RAM, which is enough for a modest utility but limits the size of source images that can be held entirely in memory. For larger projects, the binary can stream the BMP file in chunks, processing one row group at a time. Machines that need additional headroom benefit from the documentation found in upgrading the X68000 RAM to 4MB using SIP modules, which describes a practical hardware modification that keeps the system within original specifications while quadrupling available memory.

Local conditions in Australia shape how this toolchain gets used. Many enthusiasts work in home workshops that double as storage for vintage equipment. In a Brisbane garage during a humid February arvo, ambient temperatures can affect older gear, so the development machine often sits in an air-conditioned study while the X68000 lives in a cooler corner. Time differences also play a role: Japanese online auctions close in the middle of the night AEST, and parts shipments from Akihabara sellers can take weeks to clear Australian customs.

Reading and decoding the BMP container

The BMP file format is straightforward but has several variants that the utility must handle. The file begins with a 14-byte header containing the signature "BM", the file size, and an offset to the pixel data. Following this is a DIB header, which in modern files is almost always the 40-byte BITMAPINFOHEADER but could also be the older 12-byte version or extended variants. The header specifies the image width, height, bit depth, compression method, and the number of colours in the palette.

After the headers, a colour table may appear. For 8-bit BMPs, this table contains up to 256 entries of 24-bit RGB triples. For 4-bit files, the table holds 16 entries. The utility must read this table, convert each entry to the X68000's 16-bit format, and prepare it for output. Pixel data follows, stored with rows padded to 4-byte boundaries and ordered from bottom to top, which is the opposite of the X68000's native top-down arrangement.

Parsing the headers requires attention to byte order. BMP files are little-endian, which matches the 68000's native endianness, so multi-byte values can be read directly without byte-swapping. The implementation should validate the header fields: the file size in the header should match the actual file size, the reserved fields should be zero, and the pixel data offset should fall within reasonable bounds. Any deviation indicates a corrupted or non-standard file, and the utility should abort with a clear error message rather than producing garbage output.

Mapping pixels and palettes

Once the BMP is loaded into memory, the real conversion work begins. For 24-bit source images, the most complex step is colour reduction. The X68000's 16-colour mode limits the palette to 16 entries chosen from the 65,536-colour space, so the utility must select a representative set and map every pixel to the nearest match. A common approach is the median cut algorithm, which recursively splits the colour space along the longest axis until the desired number of buckets is reached, then averages the colours in each bucket to form the final palette.

Dithering helps mask the loss of colour depth. Ordered dithering using a 4×4 or 8×8 matrix adds a small amount of noise that breaks up banding in gradients, and it runs quickly enough to be practical on the 68000. Floyd-Steinberg error diffusion produces better visual results but requires more computation and memory. For utility use, ordered dithering is usually the right balance of quality and performance, particularly when processing photographs or scanned artwork.

After dithering, each pixel holds an index into the 16-colour palette. The next step arranges these pixels into the target format. For PI output, the image is divided into 16×16 tiles, and within each tile the pixel indices are packed four per byte. For raw GVRAM output, the pixels are written in the linear order expected by the video hardware, with each row padded to the appropriate boundary. The palette itself is written either to a separate file or as a header in the output container, depending on the chosen format.

Emitting a valid native image

Writing the converted image back to disk uses the standard Human68k file I/O calls. The _create DOS trap creates a new file, _write outputs data in chunks, and _close finalises the file. For a PI file, the structure begins with a small header containing the image dimensions, the number of colours, and a pointer to the tile data. The header format varies slightly between applications, so the utility should document which variant it produces, or accept a command-line flag to select the target.

The tile array follows the header. Each 16×16 tile contains 256 pixels, packed as 64 bytes in the 16-colour format. The utility iterates over the image in tile order, converting the dithered pixel buffer into the packed representation. A final checksum or magic number at the end of the file helps verify successful transfer, though many PI loaders ignore these fields and rely on the file length alone for integrity.

For raw GVRAM output, the process is simpler but less portable. The file contains only the pixel data, with no header, and the receiving program must know the resolution and colour depth in advance. This format works well for screen captures and for tools that load the data directly into video memory using IOCS calls. When the conversion finishes, the utility prints a summary on the console: the source file name, the output file name, the number of colours used, and the time taken for the conversion.

Testing on real hardware and sharing the build

Thorough testing is essential because the emulator environment rarely matches the quirks of a 35-year-old machine. The utility should be tested on multiple BMP variants: 1-bit monochrome, 4-bit indexed, 8-bit indexed, and 24-bit true colour. Each variant exercises different code paths in the parser and the converter. The output should be loaded into a real X68000 running Human68k, displayed using a simple viewer, and compared against the original image to catch palette errors, tile misalignment, or padding mistakes.

Transferring the compiled binary to a real X68000 usually involves a SCSI MO drive, a network bridge, or an SD card emulator. In Australia, the local retrocomputing community has specialists who offer SCSI bridging services for a reasonable fee, avoiding lengthy shipping delays. Local meetups in Sydney and Melbourne provide chances to test on different CRTs and compare notes. The broader scene shares tools through the X68K.NET file archive, and the wider hobbyist community includes resources such as the Zack Michaels website which collects technical references and project notes.

Once the utility is stable, distributing it as open-source encourages others to contribute improvements. The source code should build under modern GCC and under the legacy C68 compiler, and the repository should include sample BMP files and their converted outputs. Documentation in both English and Japanese widens the potential contributor base, since the X68000 community spans both language groups. Sharing the work keeps the platform alive for another generation of enthusiasts, whether they are restoring a boxed machine in Perth or building a new demo in Adelaide.

The X68000 scene depends on tools like this to keep the platform relevant. A BMP converter that runs natively on Human68k closes a loop that has been open since the community first started moving images across machines. By contributing the source, documenting the quirks, and helping others adapt the tool to new use cases, developers ensure that this corner of computing history continues to produce new art and new software. The platform's longevity rests on the willingness of enthusiasts to write the utilities that make modern workflows possible on classic hardware, and every converted image is a small victory for preservation.

Nereid-X Expansion Board

A personally-produced LAN+USB+Memory expansion board for Sharp X68000 series computers. Multiple production runs were offered, including a final batch and a later revival reproduction run.

Power Supply Repair

X68 power supply repair and modification services were offered by the site owner, with documentation shared through diary entries spanning 2001–2006.

Server & Networking

Notes on FreeBSD administration, ISP changes, server migration, and networking topics. The site itself ran on FreeBSD with the hns diary system and Namazu search integration.

A two-ink risograph print in muted slate-blue and charcoal on off-white paper, showing a stylized desktop computer monitor beside a circuit board with soft geometric trace lines, conveying a calm retro-computing workshop atmosphere. A two-ink risograph print in deep purple and dark grey on cream stock, depicting a compact expansion card with connector ports and subtle Japanese technical annotations, evoking a hobbyist electronics bench. A two-ink risograph print in teal and charcoal on warm white paper, showing a server rack silhouette with soft network-line motifs and a small weather icon, suggesting a personal server room corner.

Get in touch

X68K.NET connects Sharp X68000 enthusiasts through community links and shared projects. Reach out with questions about the Nereid project or X68 resources.