TRS-80 Tool

trs80-tool is a command-line tool for inspecting and manipulating TRS-80 files, cassettes, floppies, and hard disks. Its source code is available on Github.

Table of contents

Installation

You can download stand-alone binaries of the latest version:

Earlier versions are on the releases page.

On Linux and macOS, unzip the file to get the trs80-tool program (Safari unzips it for you):

% unzip trs80-tool-linux.zip

On macOS you’ll additionally have to remove the quarantine:

% xattr -d -r com.apple.quarantine trs80-tool

File formats

The trs80-tool program supports these file formats:

.BAS
Basic program. It’s typically tokenized (token words like PRINT are stored as a single byte), but the tool supports reading Basic programs that are in text (non-tokenized) format. When writing a file with a .BAS extension, the file is always tokenized.
.ASC
Basic program, but always in text (non-tokenized) format. The extension is mostly useful when writing a Basic file, because it tells the converter to use the non-tokenized format.
.WAV
A cassette’s audio stream. It can be at any sampling rate, either 8 or 16 bits per sample, and either mono or stereo.
.CAS
A cassette stored in a compact form where each bit on the cassette is stored as a bit in the file. It includes synchronization headers and bytes, as well as start bits (for high-speed cassettes). This is a decent archival format for cassettes.
.CMD
A machine language program as stored on a floppy disk.
.SYS
The same format as .CMD, but is meant to store system code in a disk operating system. Can also store the boot sector, in which case it’s not in .CMD format, it’s just the raw bytes.
.3BN
A machine language program as stored on a cassette. The name comes from "Model 3 BiNary". This is typically not used, and instead these files are stored within .CAS files.
.L1
A 250-baud file written by a Level 1 machine (Model 1 or 3). It can contain a system file or a Basic program.
.JV1
A floppy disk format for the Model I. It’s very simple, capturing the basic sector data. It does not capture enough information for copy-protected floppies. It’s named after Jeff Vavasour.
.JV3
A floppy disk format for the Model III. It’s very simple, capturing the basic sector data and IDAM structure. It does not capture enough information for copy-protected floppies. It’s slightly more capable than .JV1 because it can encode a mix of FM and MFM signals on the same track.
.DMK
Another floppy disk format, capturing more information from the floppy, such as some bits between sectors. Named after David M. Keil.
.DSK
Generic file extension for floppy disk—could be a .JV1, .JV3, or .DMK file. Use the info command to find out.
.SCP
SuperCard Pro raw flux floppy disk format.
.HFE
HxC Floppy Emulator floppy disk format, also used by Gotek drives. Version 1 only. Sectors can be written, but disks can’t be formatted.
.IMD
ImageDisk floppy disk format, from Dave Dunfield’s ImageDisk program. Common for Model II and other 8-inch disks. Sectors can be written, but disks can’t be formatted.
.HDV
A hard disk image, used by xtrs, sdltrs, and the FreHD hard drive emulator. LDOS 5, LS-DOS 6, and DOSPLUS 3 partitions are read; read-only.
.ASM
An assembly language file, generated by disassembling a .CMD, .SYS, or .3BN file using the disasm command.
.LST
An assembly language listing file, generated by the asm or disasm commands’ --listing flag.
.ROM
A raw machine language file, often used as the contents of ROM.
.BIN
A file of unknown type, but sometimes synonymous with .ROM.
.HEX
Intel HEX file, a text file for burning EPROMs. Can be generated by the assembler when developing a ROM.

Usage

The tool takes a command as its first argument:

% trs80-tool COMMAND args ...

Global flags work with every command:

--version Show the tool’s version number.
--help Show the usage message.
--color COLOR Set the color mode: off, 16, 256, 16m, or auto. The default, auto, detects the terminal’s color capabilities. Use the flag to turn color off, or to force it on when piping into another program. The tool also honors the NO_COLOR and FORCE_COLOR environment variables.
--no-pager Don’t send output to a pager (see below).
--trace MODULE Show trace logs for a module: base (TRS-80 file formats), emulator (the TRS-80 emulator itself), floppy (floppy-related messages), or z80 (the Z80 CPU emulator). These logs are mostly for the developer. Repeat the flag to trace several modules.
--log-file FILE Also write log messages to a file.
--no-pager Commands that can print a lot (dir, info, sectors, hexdump, and disasm) send their output to a pager when it’s going to the terminal. The pager is the TRS80_TOOL_PAGER environment variable if it’s set, then PAGER, then less (except on Windows, which only pages if one of the variables is set). Set it to cat or to an empty string, or use this flag, to turn paging off.

dir

The dir command shows the contents of an archive file. Archives files are those that can contain other files. These are cassette files (in WAV or CAS format), floppy disks (in JV1, JV3, DMK, DSK, SCP, HFE, or IMD format), and hard disks (in HDV format). Each hard disk partition's files are shown in a directory named for the partition, such as LDM3HDB.

% trs80-tool dir FILE
--system Show system files, which are normally hidden.
--cpm-records Show the sizes of CP/M text files in whole records, rather than up to the Ctrl-Z.
--json Print the directory in JSON format.

This command respects the LS_COLORS and EZA_COLORS environment variables.

info

The info command takes a list of filenames and displays a one-line description of the contents of the file, such as its type (system program, Basic program) and, if known, the embedded filename. For a hard disk, it also lists each partition, with its name, operating system, and number of files.

% trs80-tool info in1.cmd in2.bas in3.cas in4.wav in5.dmk
--verbose Show more information for some file types, such as a floppy’s geometry.
--json Print the info in JSON format. Combine with --verbose to include the extra information.

convert

The convert command converts a list of input files to an output file. There are several different ways to use this command.

A single file can be converted to another format:

% trs80-tool convert in.cmd out.3bn    (diskette to cassette format)
% trs80-tool convert in.bas out.asc    (de-tokenize Basic program)

Several files can be put into an archive:

% trs80-tool convert in1.bas in2.3bn in3.cmd out.wav

This creates a cassette audio file containing the three files. Note that the .CMD file will be converted to .3BN format.

Floppies, hard disks, .CAS files, and cassette audio files are expanded into the files they contain, so they can be converted to other archive formats:

% trs80-tool convert in.dmk out.wav
% trs80-tool convert in.wav out.cas

The output must be a file; to extract the contents of an archive, use extract.

A floppy image can be converted to another floppy image format. If the input is a floppy image and the output ends in .dmk, .jv1, .jv3, .hfe, or .imd, the whole disk is converted to that image format, whatever file system it has (or if it has none). The input can be any floppy image the tool reads: DMK, JV1, JV3, HFE, IMD, or SCP.

% trs80-tool convert in.dmk out.hfe
Wrote out.hfe: HFE floppy, 40 cylinders, 1 side, 720 sectors; nothing lost.
% trs80-tool convert in.imd out.dmk

(.dsk isn’t accepted for the output, because it means JV1 to some programs and JV3 to others: use .jv1 or .jv3.)

.dmk Keeps every track as bytes. Converting from HFE keeps the bytes of the tracks (gaps, sync bytes, and copy protection); from the sector formats (JV1, JV3, IMD) the tracks are laid out as a DOS’s FORMAT would have, with real CRCs. Holds anything, including both densities on one track.
.hfe Version 1 images for Gotek drives and the HxC emulator, with the same header as the images made on real TRS-80 hardware. Every track is exactly one turn long (100,000 cells a side for a 5¼-inch disk). Converting from DMK keeps the bytes of the tracks. An ID field with no data field after it can’t be kept, because the HFE reader finds sectors by their data marks.
.jv3 Holds sectors of 128 to 1,024 bytes in either density, with their order around the track, deleted marks, and CRC errors. It can’t hold IDs that disagree with where the sector is, duplicate sector numbers, sectors without data, bad ID CRCs, or sector numbers above 39.
.imd Holds one density per track, any sector size, the order of the sectors, IDs that disagree with their position, sectors without data, deleted marks, and data errors. It can’t hold which deleted mark (0xF8, 0xFA) was used, or bad ID CRCs. Disks of 8 inches are written at 500 kbit/s, and 5¼-inch ones at 250.
.jv1 Holds only single-sided, single-density tracks of ten 256-byte sectors numbered 0 to 9. Anything else is left out, tracks with missing sectors are filled with 0xE5, and its deleted marks are those it makes up for cylinder 17.

After converting, the tool reads the new image back and compares every sector with the original (its data, ID field, density, deleted mark, and CRC errors), and, if the disk has a file system the tool recognizes, every file. It then reports what the new format couldn’t hold, counted by kind, with a few examples of each:

% trs80-tool convert protected.dmk out.jv3
JV3 can't hold everything on this disk:
  2 sectors missing
    cylinder 0 side 0 sector 125: sector is missing
    cylinder 0 side 0 sector 127: sector is missing
  11 sectors whose ID field CRC error changed
    cylinder 19 side 0 sector 16: ID field has a bad CRC, so the sector was dropped
    and 8 more
Note: 35 tracks whose gaps and sync bytes are regenerated
Nothing was written to "out.jv3". Use --force to write it anyway.
% trs80-tool convert --force protected.dmk out.jv3
% trs80-tool convert in.jv3 out.dmk
Wrote out.dmk: DMK floppy, 40 cylinders, 2 sides, 1,440 sectors; nothing lost.

If anything would be lost, nothing is written unless you give --force. Differences that lose nothing (the interleave of the sectors, sectors added to fill a track, and the gaps of a track that is stored as sectors) are shown as notes and don’t need --force. Converting a disk to its own format makes a copy. To get the files out of a disk, use extract; to make a new disk, use disk.

--force Write a floppy image even if the new format can’t hold everything on the disk.
--baud RATE Write cassettes at this baud rate (250, 500, or 1500). If not specified, it will be guessed, if possible, otherwise will be 500 baud (low speed).

--start ADDRESS Set the start address of a system program, or auto to guess one. For .BIN and .ROM input, this is also the load address.
--system Include system files from floppies and hard disks.
--cpm-records Keep the whole records of CP/M text files (see extract).

If a system program doesn’t have a built-in start address, the info command shows the one it guesses, which you can then set:

% trs80-tool info in.cas
in.cas: System program (VCEPRN, /17408) on a low speed cassette
% trs80-tool convert --start 17408 in.cas out.cas
Wrote out.cas: System program (VCEPRN) in low speed CAS file
% trs80-tool info out.cas
out.cas: System program (VCEPRN) on a low speed cassette

More examples:

% trs80-tool convert --baud 1500 in1.bas in2.3bn out.wav
% trs80-tool convert --start 0x1024 in.rom out.cmd

extract

The extract command writes the files inside a floppy image, hard disk image, .CAS file, or cassette audio file to a directory. The files go into the current directory unless you give --out-dir, which creates the directory if it doesn’t exist. Files already in the directory with the same names are overwritten.

% trs80-tool extract in.dmk
% trs80-tool extract in.dmk --out-dir out
% trs80-tool extract in.hdv --out-dir out
% trs80-tool extract in.cas --out-dir out
% trs80-tool extract in.wav --out-dir out

A hard disk’s files go into a subdirectory for each partition, named for the partition, as in out/LDM3HDB/BASIC.CMD.

To extract only some of the files, name them after the input file. Each name is matched against the names of the files on the disk (as dir shows them), not against files on your computer, and may have wildcards:

% trs80-tool extract in.dmk "*.bas"
% trs80-tool extract in.dmk HELLO.BAS GOODBYE.BAS --out-dir out
% trs80-tool extract in.hdv "LDM3HDB/*.CMD" --out-dir out

Quote the names that have wildcards, so that your shell doesn’t expand them against the files in the current directory first. Matching ignores case. A * matches any number of characters except /, a ? matches one character other than /, and ** matches any characters including /. Every other character matches itself. On a hard disk or Xenix floppy, whose files are in directories, a name without a / is matched against the last part of each path, so "*.CMD" finds the .CMD files in every directory; a name with a / is matched against the whole path. Elsewhere a / in the name means ., so HELLO/BAS finds HELLO.BAS. It’s an error if a name matches no files, and nothing is written.

--out-dir DIR Write the files to this directory, which is created if needed. The default is the current directory.
--system Include system files from floppies and hard disks.
--cpm-records Keep the whole records of CP/M text files, rather than stopping at the Ctrl-Z.
--ucsd-pascal-raw Write UCSD Pascal text files as they are on the disk, rather than converting them to plain text.
--lowercase Write the files with lowercase names.
--mark-damaged Add [DAMAGED] to the names of damaged files, as in HELLO.BAS [DAMAGED].
--json Print a JSON object to standard output instead of writing files. Only the files that match the names, if any, are included. The JSON includes the contents of each file in base64. This can’t be used with --out-dir.

disk

The disk command works on one floppy or hard disk image: it lists, extracts, adds, removes, and renames files, changes attributes and labels, maps, checks, and repairs the file system, creates and formats new disks, and boots the disk in the emulator. Give the image, then one or more commands separated by a lone :, or no commands for an interactive prompt.

% trs80-tool disk in.dmk dir
% trs80-tool disk in.dmk extract "*.bas" --out-dir out : free
% trs80-tool disk games.dmk create ldos-5.3 : add *.bas

It has its own page: the disk command.

hexdump

The hexdump command displays a hex dump of the input file, with annotations.

% trs80-tool hexdump in.cmd
--no-collapse Show every line, rather than collapsing identical ones.

sectors

The sectors command displays a table of the sectors in a floppy disk. The columns are the sectors and the rows are the tracks. For each sector a character is displayed:

- No sector.
S Single-density sector.
D Double-density sector.
X Deleted sector.
C CRC error (ID or data).
? Missing sector.
--contents Also show the contents of the sectors.
--bad Instead of the table, list the sectors that are missing or that have a CRC error, and which file (if any) is on each one. Floppies without bad sectors are left out.
--json Print the sector information in JSON format, with a description of each sector instead of the table. Combine with --contents to include each sector’s data in base64, and with --bad to include only the bad sectors.

asm

The asm command assembles the specified assembly language source code:

% trs80-tool asm program.asm program.cmd
% trs80-tool asm --baud 1500 program.asm program.cas
% trs80-tool asm --listing program.lst program.asm program.cmd

It can generate .CMD, .3BN, .CAS, .WAV, BIN, or HEX files.

--baud RATE The baud rate for .CAS and .WAV files: 250, 500 (the default), or 1500.
--listing FILE Also write a listing file.
--model MODEL The target model: 1, 3 (the default), or 4.

The assembler defines the constants __MODEL__ (the number of the target model) and __MODEL_1__, __MODEL_3__, and __MODEL_4__, which can be used with if, else, and endif to write code that differs between models:

	if __MODEL__ == __MODEL_1__
	ld a,(0x37E0)
	else
	in a,(0xEC)
	endif

disasm

The disasm command disassembles the specified program:

% trs80-tool disasm saucer.cmd
% trs80-tool disasm --org 0x8000 file.bin
% trs80-tool disasm --entry 0x0000,0x3799,0x377B model3.rom
% trs80-tool disasm --listing program.cmd

If the program is a .CMD, .SYS, or .3BN file, it is loaded into the correct place in memory. If it’s a .ROM or .BIN file, it is loaded at 0x0000.

The disassembler tries to guess which bytes are code and which are data by following the path of the program, starting with its main entry point.

--org ADDRESS Load a .ROM or .BIN file at this address rather than 0x0000.
--entry ADDRESSES Add entry points (comma-separated).
--full Disassemble straight through the program rather than following its path, so bytes that are data are disassembled too.
--data-comment Comment each instruction with the ASCII of its bytes, to make data easier to find with --full.
--no-labels Don’t create labels for jump targets.
--no-known Don’t refer to known ROM addresses by name.
--hex-format FORMAT The format of hex numbers: c for 0x12 (the default), dollar for $12, or h for 12h.
--upper Write assembly language in upper case.
--listing Write a listing instead of assembly language.
--no-binary Leave the opcode bytes out of the listing.

run

Run a TRS-80 emulator in the shell. This is experimental and does not currently work well with games, and may not work at all in a Microsoft Windows shell. Specify a program or floppy to load and run directly:

% trs80-tool run
% trs80-tool run tdos13a.dsk
% trs80-tool run frogger.cmd
% trs80-tool run --model 1 --level 1
% trs80-tool run --mount in.cas in1.dmk in2.dmk in3.dmk

Floppies, including one given as the program to run, are write-protected unless you specify --writable.

--model MODEL The model: 1, 3 (the default), or 4.
--level LEVEL The Basic level: 1 or 2 (the default).
--mount FILES... Mount a cassette and floppies. Only one cassette may be mounted, but several floppies can be mounted.
--writable Let the emulator write to floppies, and save the changes to their files. A floppy stays write-protected, with a warning, if its file is read-only or its image (DMK, JV3, or HFE) is marked write-protected.
--printer FILE Write printer output to a file, rather than showing it below the screen.
--xray Show nothing in the shell, but start a web server for the X-ray debugger. This is experimental and not yet documented.

repl

Starts an interactive session for exploring the Z80. Type help to get a list of commands. Type an assembly language instruction (such as ld a,5) to assemble it, write it to memory, explain it, execute it, and show its effects on flags and registers. This virtual machine is not in a TRS-80 context (it has no ROM or peripherals).

mcp

Runs an MCP server on stdin/stdout, which lets an AI assistant drive a TRS-80 directly. The assistant can boot a ROM, type at it, run it for an exact number of clock cycles, and inspect the screen, memory, and registers. The machine stays running between requests, so the assistant can explore interactively instead of guessing.

You don’t run this command yourself. Your AI tool starts it for you, so what you do is tell that tool about it. With Claude Code:

% claude mcp add --scope user trs80 -- trs80-tool mcp

Other MCP clients use a JSON configuration file. The entry looks like this:

{
    "mcpServers": {
        "trs80": {
            "command": "trs80-tool",
            "args": ["mcp"]
        }
    }
}

In both cases trs80-tool must be on your PATH. If it isn’t, use the full path to the binary instead. MCP servers are started when your AI tool starts, so restart it after adding this.

These are the tools the assistant gets:

Timings are reported in Z80 clock cycles (t-states) rather than wall-clock time, so they’re exact and repeatable no matter how fast the emulator happens to run on your machine.

help

The help command shows more specific information about other commands:

% trs80-tool help dir
% trs80-tool help convert

Limitations

Change log

This change log covers the tool and the related web apps (My TRS-80, the IDE, and the cassette reader). Run trs80-tool --version to see which version you have.

November 7, 2026

October 24, 2026

October 22, 2026

October 21, 2026

October 19, 2026

October 15, 2026

October 14, 2026

October 13, 2026

October 12, 2026

October 10, 2026

October 1, 2026

September 14, 2026

September 9, 2026

July 29, 2026

June 9, 2026

June 7, 2026

May 12, 2026

April 5, 2026

March 28, 2026

March 10, 2026

March 6, 2026

December 9, 2025

December 16, 2024

December 13, 2024

April 12, 2024

December 31, 2023

October 4, 2023

March 14, 2023

November 3, 2022

January 30, 2022

November 6, 2021

September 29, 2021

September 7, 2021

August 29, 2021

July 31, 2021

May 29, 2021

May 22, 2021

May 21, 2021

May 16, 2021

May 15, 2021