Contents
6dcli — reading and editing a .6diss from a script
6dcli is the console front end, in the 6diss download. What it prints is the listing the GUI draws, from the same
disassembler, with the same knowledgebase annotations and the same cross-file xrefs.
It exists for the round trip in Claude integration, Step 3: read a file the way the window reads it, reason about it somewhere else, write the answers back without hand-editing JSON.
Reach for --live first. With it, every command below goes to a running 6diss over
the control channel instead of to a file — same verbs, no project
argument, and the answers include everything not yet saved. This page is the file-based
half: for when nothing is running, or when the project is not the one that is open.
Commands
6dcli files <project> |
every binary: module, name, address range, label count, packer, notes |
6dcli list <project> <module> [--from $2dc8] [--to $2e40] [--plain] |
the rendered listing |
6dcli labels <project> <module> [--from …] [--to …] [--user] |
labels, --user hides the Auto ones |
6dcli xrefs <project> <module> <addr> |
what reaches an address, from this file and from the others |
6dcli bytes <project> <module> <addr> [--len 64] |
hex + ASCII |
6dcli rename <project> <module> <addr>=<name>[:comment] … |
set labels |
6dcli comment <project> <module> <addr>=<text> … |
set annotations |
6dcli docs <project> |
the project's notes: title, file, size, first line |
6dcli doc <project> <title> |
print one note |
6dcli write-doc <project> <title> [--append] [--text …] |
write one; text comes from stdin unless --text is given |
Addresses are hex, with or without $. rename takes --role sub\|loc\|data and
--origin user\|assistant; comment takes --block for a line above rather than beside.
files also takes --pattern 'MON*' and --summary. On a project with more than about
fifty files, start with --summary: it groups by name family and reports how many of
each, what sizes they come in and where they load, which is the shape of the release. The
list of eight hundred names is the least useful true thing 6diss can say about it.
Answers onto disk, and the analyses
These work against the file with no window running.
dump <project> <module> <out.lst> [--from …] [--to …] [--plain] |
the listing, as a file you can grep |
dump <project> <module> <out.bin> --bytes [--from …] |
an address range, as raw bytes |
dump <project> --all --directory <dir> [--pattern …] [--header] |
every file's image, plus a manifest.tsv of load addresses |
decode <project> <module> [<addr>] [--kind …] [--stride N] |
a table's values — pointer targets, strings, a jump table's 32 destinations |
variance <project> <glob> [--varying-only] |
which byte offsets carry information, across a family |
variance <project> <module> --stride 480 |
the same, over the records inside one file |
compare <project> <module> <other> [--stride N] |
equal, or exactly which offsets differ |
compare <project> --all [--pattern …] |
which files are really the same file — and which names carry two different builds |
graph <project> <module> [--calls-only] |
control-flow targets with caller counts |
graph <project> <module> --touched write --from '$d000' --to '$dfff' |
every address the code reads or writes |
pointers <project> <module> --strings-from '$9400' |
find a pointer table nobody declared |
pointers <project> <module> --validate '$9658' |
does the table you declared actually land? |
registers <project> <module> [--from …] [--known-only] |
what A, X and Y hold at each instruction |
run <project> <module> [--entry …] [--a N] [--write-to f.bin] |
execute it, and report what changed |
run is not a C64 — no VIC, no SID, no interrupts, $D000-$DFFF is plain RAM. It runs a
routine against a snapshot of the project's memory and tells you what it wrote. Everything
that needs a real machine still needs VICE, and that is a boundary rather than a shortfall.
dump --all deserves a note. A project imported from eight disk sides already holds every
byte; re-extracting them from the D64s to run a format decoder over them is doing work 6diss
has already done, and it throws away the load addresses the project worked out. The manifest
carries those.
--live only
The rest of the menu needs a window to run it in — an undo stack, a listing to redraw, and
a user watching — so these exist under --live and nowhere else:
load-address <module> <addr> [--header 2] [--embedded] |
where the file really runs; everything moves with the bytes |
describe <module> [--description …] [--notes …] [--module-name …] [--tool ecl\|--no-tool] |
the banner at the top of the file, and which tool renders it |
same-file <module> [<original>] [--clear] |
that file is this file: borrow its recipe instead of writing a second one |
same-file --all [--pattern …] |
pair up every byte-identical file at once, and report the names carrying two builds |
invoke [<command>] / screenshot <out.png> / measure [<control>] |
the window itself, for working on 6diss |
define <module> <addr> <name>[:comment] [--scope file\|owner\|project] |
name an address the file refers to |
constant <module> <value> <name> [--scope project\|file\|instruction] [--site …] |
name a value; $1b is hex, 27 is decimal |
move-label <module> <to> [--from …] |
put a label on the byte it belongs to |
address-load <module> <target> --low … --high … [--name …] |
the two immediates that are halves of one address |
overlay <module> <start> <end> <exec> [--kind DriveCode] |
this block runs somewhere else |
ref <module> <target-module> [--site …\|--from …\|--file] |
which file a reference means; "" for none |
split <module> <addr> … / --path f.txt / --every N / --clear |
where a line starts inside a table; a list is one call and one undo step |
retrace <module> |
re-trace from the entry points |
find-code, detect, brain <module> [--apply] [--accept 0,3,7] |
propose, then accept what you believe |
players <module> [--apply] |
which playroutine is in here |
depack <module> --from … --to … [--apply] |
ask 6crunch about a range |
regions <module> |
what has been classified, and the overlays |
find <text> [--project] [--bytes] [--match-case] |
text, names, operands or a9 ?? 8d 20 d0 |
export <directory> [--exact] |
6asm source; --exact writes a build.sh that compares |
render <module> <out.png> [--kind Charset] [--from …] |
a charset, sprites or a bitmap as a picture |
source-tool [--match 'ECL??'] [--tool ecl] [--command …] [--input prg\|raw] [--comment ';'] [--clear] |
render a file with a tool that isn't 6diss |
find-code, detect and brain print an indexed proposal list and apply nothing. Read
it, then run the same command with --apply --accept 0,3,7. That is the review dialog the
window opens, kept rather than dropped.
Any <module> above also accepts a glob. region 'MON*' $7c00 $7c0f TextAscii is one
decision, so it is one call and one Ctrl+Z rather than sixty-nine of each. The undo depth
is what makes this matter rather than the process count: the stack is a hundred steps deep,
so a sweep applied one step at a time did not merely make undo tedious, it swallowed every
step in front of it. rename, comment and split also take --path, so a list a session
has just written is a list 6diss can read.
The note commands are exempt from the rule below, because they never touch the .6diss:
a note is a .md in <project>.docs/ beside it, and the project reads whatever is in that
folder when it opens. Writing one under a running 6diss is safe, and write-doc on a title
the project does not know creates the file and says it will be listed the next time the
project is opened. To have it appear now, use --live.
The one rule
6diss writes the whole project file when it saves. A write underneath a running 6diss
is gone the moment the user hits Ctrl+S. So rename and comment:
- ask every running instance over the control channel whether it has this project open,
and refuse if one does — pointing at
--live, which has no such problem; - copy the project to
<name>.6diss.bakbefore saving.
If no instance answers — an older build, the channel switched off — nothing is known to be
at risk and the write goes ahead. --force overrides the refusal, and still means the user
must reopen the project rather than save over it.
Reading a listing without drowning
— unclaimed on a line means "this address is inside several files' ranges and none of them
owns it" — noise when the address is RAM that overlays share, which in an overlay-based game
is most of it. It used to be worse than noise: the note named every candidate, so on an
820-file project an address touched by 250 of them put 250 file names on every line
referring to it, and a 24-instruction routine rendered as about 15,000 tokens. The
disassembler now names three and counts the rest, and drops the note entirely past a
couple of dozen candidates.
If you still want it gone entirely:
6dcli list game.6diss LIBRARY \
| sed -E 's/ *; (in|also in) [A-Z_0-9, ]*— unclaimed//; s/ +; TBUFFR\+[0-9]+.*//'
The better answer for a long listing is dump, which writes it to a file — then grep it
rather than reading it through a pipe.