mirror of
https://github.com/fadden/6502bench.git
synced 2024-08-20 11:28:58 +00:00
Before: Hint As Code Entry Point Hint As Data Start Hint As Inline Data Remove Hints After: Tag Address As Code Start Point Tag Address As Code Stop Point Tag Bytes As Inline Data Remove Analyzer Tags The goal is to reduce confusion. The old nomenclature was causing problems because it's inaccurate -- they're directives, not hints -- and made it look like you need to mark data items explicitly. The new action names emphasize the idea that you should be tagging a single address for start/stop, not blanketing a region. This change updates the user interface, manual, and tutorials, but does not change how the items are referred to in code, and does not change how the program works. (issue #89)
984 lines
43 KiB
HTML
984 lines
43 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
|
|
<head>
|
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<link href="main.css" rel="stylesheet" type="text/css" />
|
|
<title>Intro - 6502bench SourceGen</title>
|
|
</head>
|
|
|
|
<body>
|
|
<div id="content">
|
|
<h1>6502bench SourceGen: Intro</h1>
|
|
<p><a href="index.html">Back to index</a></p>
|
|
|
|
<h2><a name="overview">Overview</a></h2>
|
|
|
|
<p>SourceGen converts 6502/65C02/65816 machine-language programs to
|
|
assembly-language source.</p>
|
|
|
|
<p>SourceGen has two purposes. The first is to be a really nice
|
|
disassembler for the 6502 and related CPUs. Code tracing with status
|
|
flag tracking makes it easier to separate the code from the data,
|
|
automatic formatting of character strings and filled-data areas helps
|
|
get the data regions sorted out, and modern IDE-style features like
|
|
cross-reference generation and color-highlighted bookmarks help
|
|
navigate the code while trying to figure out what it does. A
|
|
disassembler should help you understand the code, not just dump the
|
|
instructions to a text file.</p>
|
|
<p>The computer I built back in 2014 has a 4GHz CPU and 8GB of RAM. I
|
|
figured we should put the power of modern computing hardware to good use.</p>
|
|
|
|
<p>The second purpose is to facilitate sharing and collaboration. Most
|
|
disassemblers generate output for a specific assembler, or in a way that's
|
|
generic enough to match most any assembler; either way, you're left with
|
|
a text file in somebody's idea of the "correct" format. SourceGen keeps
|
|
everything in an assembler-neutral format, and provides numerous options
|
|
for customizing the display, so that multiple people viewing the same
|
|
project can each do so with the conventions they are accustomed to.
|
|
Code and data operands can be formatted in various numeric formats or
|
|
as symbols.
|
|
The project file uses a text format that is fairly diff-friendly, so
|
|
sharing projects through git works reasonably well. If you want source
|
|
code you can assemble, SourceGen will generate code optimized for the
|
|
assembler of your choice.</p>
|
|
|
|
<p>The sharing and collaboration ideas only work if the formatting
|
|
capabilities within SourceGen are sufficiently flexible. If you need to
|
|
generate assembly source and tweak it a bunch to express the intent of
|
|
the original code, then passing a SourceGen project around won't work.
|
|
This sort of thing is a bit outside the bounds of what a typical
|
|
disassembler does, so it remains to be seen whether SourceGen succeeds at
|
|
what it's trying to do, and also whether what it's trying to do is
|
|
something that people actually want.</p>
|
|
|
|
<p>You can get started by watching the
|
|
<a href="https://youtu.be/dalISyBPQq8">demo video</a> and playing with the
|
|
<a href="tutorials.html">tutorials</a>.</p>
|
|
|
|
|
|
<h2><a name="fundamental-concepts">Fundamental Concepts</a></h2>
|
|
|
|
<p>The next few sections present some general concepts and terminology. The
|
|
rest of the documentation assumes you've read and understood this.</p>
|
|
<p>It will be helpful if you already understand something about the 6502
|
|
instruction set and assembly-language programming, but disassembling
|
|
other programs is actually a pretty good way to learn how to code in
|
|
assembly. You will need to be familiar with hexadecimal numbers and
|
|
general programming concepts to make sense of this, however.</p>
|
|
|
|
<h2><a name="begin">About 6502 Code</a></h2>
|
|
|
|
<p>For brevity's sake, "6502 code" should be taken to mean "code for
|
|
the 6502 CPU or any of its derivatives, including but not limited to
|
|
the 65C02 and 65816". So let's talk about 6502 code.</p>
|
|
|
|
<p>Code usually arrives in a big binary blob. Some of it will be
|
|
instructions, some of it will be data, some will be empty space used
|
|
for variable storage. Part of the challenge of disassembly is
|
|
identifying which parts of the file contain which.</p>
|
|
|
|
<p>Much of the code you'll find for the 6502 was written by humans,
|
|
rather than generated by a compiler, which means it won't conform to a
|
|
standard set of conventions. However, most programmers will use
|
|
subroutines, which can be identified and analyzed in isolation. Subroutines
|
|
are often interspersed with variable storage, referred to as a "stash".
|
|
Variables and constants may be single-byte or multi-byte, the latter
|
|
typically in little-endian byte order.</p>
|
|
|
|
<p>Much of the data in a typical program is read-only, often in the
|
|
form of graphics or character string data. Graphics can be difficult
|
|
to recognize automatically, but strings can be identified with a
|
|
reasonable degree of confidence. Address tables, which are a collection
|
|
of addresses to other things, are also fairly common.</p>
|
|
|
|
<p>A simple disassembler would start at the top of the file and just
|
|
start converting bytes to instructions. Unfortunately there's no reliable
|
|
way to tell the difference between instructions, data, and variable
|
|
stashes. When the converter hits data bytes it'll start generating
|
|
instructions that won't make sense. You'll have another problem when the
|
|
data ends and code resumes: 6502 instructions are variable-length, so if
|
|
the last byte of the data area appears to be a three-byte instruction,
|
|
the first two bytes of the next instruction area will be gobbled up.</p>
|
|
|
|
<p>To make things even more difficult (sometimes deliberately), programmers
|
|
will sometimes use a trick where they "embed" an instruction
|
|
inside another instruction. This allows code to branch to two different
|
|
entry points, one of which will set a flag or load a register, and then
|
|
continue on to common code.</p>
|
|
|
|
<p>Another trick is to embed "inline data" after a JSR or JSL instruction.
|
|
The called subroutine pulls the caller's address off the stack, uses it to
|
|
access the parameters, then pushes the address back on after modifying it to
|
|
point to an address past the inline data. This can be very confusing
|
|
for the disassembler, which will try to interpret the inline data as
|
|
instructions.</p>
|
|
|
|
<p>Sometimes code is loaded at one location, then moved to another and
|
|
executed there. If you're disassembling an executing program you don't
|
|
have to worry about this, but if you're disassembling the binary from the
|
|
loadable file on disk then you need to track the address changes. The
|
|
address is communicated to the assembler with a "pseudo-opcode", usually
|
|
something like "ORG". Other pseudo-op directives are used to define external
|
|
symbols and (for 65816 code) register widths.</p>
|
|
|
|
<p>The 8-bit CPUs have a 16-bit (64KiB) address space, so addresses can
|
|
range from $0000 to $ffff. (I'm going to write hex values with a
|
|
preceding '$', like "$12ab", rather than "0x12ab" or "12abh", because
|
|
that's what 6502 systems commonly used.) The 65816 has a 24-bit address
|
|
space, but it's not contiguous -- a branch that extends past the end will
|
|
wrap around to the start of the 64KiB "bank". For 16-bit instruction
|
|
operands, the bank is identified for instruction and data addresses
|
|
by the program bank register and the data bank register, respectively.
|
|
The disassembler can't always discern the value of the data bank
|
|
register through static analysis, so some user input may be required.</p>
|
|
|
|
<p>The 6502 has an 8-bit processor status register ("P") with a bunch of flags
|
|
in it. Some of the flags determine whether a conditional branch is taken
|
|
or not, which is important because some branches appear to be conditional
|
|
but actually are always or never taken in practice. The disassembler needs
|
|
to be able to figure this out so that it doesn't try to disassemble the
|
|
bytes that follow an always-taken branch.
|
|
A more significant concern is the M and X flags found on the 65802/65816,
|
|
which determine the width of the registers and of immediate load
|
|
instructions. If you don't know what state the flags are in, you can't
|
|
know whether <code>LDA #value</code> is two bytes or three, and the
|
|
disassembly of the instruction stream will come out wrong.</p>
|
|
|
|
<p>Some addresses correspond to memory-mapped I/O, rather than RAM or ROM.
|
|
Accessing the address can have side effects, like changing between text
|
|
and graphics modes. Sometimes reading and writing have different effects.
|
|
For example, on later models of the Apple II, reading from
|
|
$C000 returns the most recently hit key, while writing to $C000 changes
|
|
how 80-column display memory is mapped.</p>
|
|
<p>On a few systems, such as the Atari 2600, RAM, ROM, and registers can
|
|
appear at multiple locations, "mirrored" across the address space.</p>
|
|
|
|
<h3><a name="charenc">Character Encoding</a></h3>
|
|
|
|
<p>The American Standard Code for Information Interchange (ASCII) was
|
|
developed in the 1960s, and became widely used as the means for representing
|
|
text data on a computer. It's compatible with Unicode, in that the
|
|
binary representation of an ASCII string is exactly the same when
|
|
expressed as a Unicode string with UTF-8 encoding.</p>
|
|
<p>Not all 6502-based computers used ASCII, notably those from Commodore
|
|
International (e.g. PET, VIC-20, 64, 128), which used variants
|
|
collectively known as "PETSCII". PETSCII had most of the same symbols,
|
|
but rearranged them, and added a number of graphical symbols. This was
|
|
further complicated by the use of two different character sets, one of
|
|
which dropped lower-case letters in favor of additional symbols, and
|
|
the use of a separate encoding for characters stored in the text frame
|
|
buffer ("screen codes").</p>
|
|
<p>Apple II computers were based on ASCII, but tended to store bytes
|
|
with the high bit set rather than clear. This is known as "high ASCII".</p>
|
|
|
|
<p>SourceGen allows you to specify that a string is encoded with ASCII,
|
|
High ASCII, C64 PETSCII, or C64 Screen Codes. Because the goal is to
|
|
generate assembly sources for cross-assemblers, the C64 character
|
|
support is limited to the set that overlaps with ASCII.</p>
|
|
<p>For the most part only printable characters are accepted in strings,
|
|
but certain control characters are also allowed. The characters for
|
|
bell ($07), linefeed ($0a), and carriage return ($0d) are recognized as
|
|
string data, and in C64 PETSCII a number of text color and formatting
|
|
control codes are also allowed.</p>
|
|
|
|
|
|
<h2><a name="sgintro">How SourceGen Works</a></h2>
|
|
|
|
<p>SourceGen employs a partial emulation technique that traces the flow
|
|
of execution. Most of what a given instruction does isn't important;
|
|
only its effect on the flow of execution matters.</p>
|
|
|
|
<p>The code tracing has to start somewhere, so SourceGen uses "code start
|
|
points" to identify places where execution may begin. By default,
|
|
the first byte of the file is tagged as a start point. From there, the
|
|
tracing process walks through the code, pursuing all branches. In many
|
|
cases, if you tag all external entry points, SourceGen will automatically
|
|
find all executable code and separate it from variable storage and
|
|
data areas.</p>
|
|
|
|
<p>As noted earlier, tracking the processor status flags can make the
|
|
analysis more accurate. Identifying situations where a branch instruction
|
|
is always or never taken avoids mis-categorizing a data region as code.
|
|
On the 65816, it's absolutely crucial to track the M/X flags, since those
|
|
affect the width of instructions. SourceGen tracks the value of the
|
|
processor flags at every instruction, blending sets of flags together when
|
|
multiple paths of execution converge.</p>
|
|
|
|
<p>Once instructions and data have been separated, the instruction operands
|
|
can be examined. Branches, loads, and stores that reference an address
|
|
that falls inside the address space covered by the file can be replaced
|
|
with a symbol. Operands that refer to addresses outside the file, such
|
|
as ROM or operating system routines, can be replaced with a symbol defined
|
|
by an equate directive.</p>
|
|
|
|
(For more details on how this works, see the
|
|
<a href="analysis.html">analysis appendix</a>.)
|
|
|
|
|
|
<h3><a name="scripts">Extension Scripts</a></h3>
|
|
|
|
<p>Extension scripts are C# source files that are compiled and
|
|
executed by SourceGen. They can be added to a project from SourceGen's
|
|
runtime data directory, or can live in the directory next to the project
|
|
file.</p>
|
|
<p>In the current implementation, scripts are only called to examine
|
|
JSR, JSL, and BRK instructions. They can format nearby bytes as inline
|
|
data, or apply symbols to operands.</p>
|
|
|
|
<p>To reduce the chances of a script causing problems, all scripts are
|
|
executed in a sandbox with severely restricted access. Notably, nothing
|
|
in the sandbox can access files, except to read files from the PluginDll
|
|
directory.</p>
|
|
<p>The PluginDll directory lives next to the SourceGen executable, and
|
|
contains all of the compiled script DLLs, as well as two pre-built
|
|
application DLLs that plugins are allowed access to. The contents
|
|
are persistent, to avoid recompiling the scripts every time SourceGen
|
|
is launched, but may be manually deleted without harm.</p>
|
|
<p>More details can be found in the
|
|
<a href="advanced.html#extension-scripts">advanced topics</a> section.</p>
|
|
|
|
|
|
<h3><a name="atags">Code Analyzer Stop, Start, and Skip</a></h3>
|
|
|
|
<p>Sometimes SourceGen can't automatically find the start or end of an
|
|
instruction stream, or gets confused by inline data. These situations
|
|
can be resolved by adding analyzer tags.</p>
|
|
|
|
<p><b>Code start point</b> tags tell the analyzer to add the offset
|
|
to the list of instruction start points. Suppose you've got a code
|
|
library that begins with jump vectors, like this:</p>
|
|
<pre>
|
|
1000: 4c0910 JMP $1009
|
|
1003: 4cef10 JMP $10ef
|
|
1006: 4c3012 JMP $1230
|
|
1009: 18 CLC
|
|
</pre>
|
|
|
|
<p>When opened with SourceGen, it will look like this:</p>
|
|
<pre>
|
|
.ORG $1000
|
|
JMP L1009
|
|
|
|
.DD1 $4c
|
|
.DD1 $ef
|
|
.DD1 $10
|
|
.DD1 $4c
|
|
.DD1 $30
|
|
.DD1 $12
|
|
L1009 CLC
|
|
</pre>
|
|
|
|
<p>SourceGen doesn't see any code that jumps to $1003 or $1006, so it
|
|
assumes those are data. Further, the functions at those addresses may
|
|
also be considered data unless some bit of code reachable from L1009
|
|
calls into them. If you tag $1003 and $1006 as code start points,
|
|
you'll get better results:</p>
|
|
<pre>
|
|
.ORG $1000
|
|
JMP L1009
|
|
JMP L10ef
|
|
JMP L1230
|
|
L1009 CLC
|
|
</pre>
|
|
|
|
<p>Be careful that you only tag the instruction opcode byte. If
|
|
you tagged each and every byte from $1003 to $1008, you would
|
|
end up with a mess:</p>
|
|
<pre>
|
|
.ORG $1000
|
|
JMP L1009
|
|
JMP ▼ L10ef
|
|
BPL ▼ L1053
|
|
JMP ▼ L1230
|
|
BMI L101b
|
|
L1009 CLC
|
|
</pre>
|
|
|
|
<p>The exact set of instructions shown depends on your CPU configuration.
|
|
The problem is that the bytes in the middle of the instruction have
|
|
been tagged as start points, so SourceGen is treating them as
|
|
embedded instructions. $EF and $12 aren't valid 6502 opcodes, so
|
|
they're being ignored, but $10 is BPL and $30 is BMI. Because tagging
|
|
multiple consecutive bytes is rarely useful, SourceGen only applies code
|
|
start tags to the first byte in a selected line.</p>
|
|
|
|
<p><b>Code stop point</b> tags tell the analyzer when it should stop. For
|
|
example, suppose address $ff00 is known to always be nonzero, and the code
|
|
uses that fact to get a branch-always on the 6502:</p>
|
|
<pre>
|
|
.ORG $1000
|
|
LDA $ff00
|
|
BNE L1010
|
|
BRK $11
|
|
</pre>
|
|
|
|
<p>By tagging the BRK as a code stop point, you're telling the analyzer that
|
|
it should stop trying to execute code when it reaches that point. (Note
|
|
that this example would actually be better solved by setting a status flag
|
|
override on the BNE that sets Z=0, so the code tracer will know it's a
|
|
branch-always and just do the right thing.) As with code start points,
|
|
code stop points should only be placed on the opcode byte. Placing a
|
|
code stop point in the middle of what SourceGen believes to be instruction
|
|
will have no effect.</p>
|
|
<p>As with code start points, only the first byte in each selected line will
|
|
be tagged.</p>
|
|
|
|
<p><b>Inline data</b> tags identify bytes as being part of the
|
|
instruction stream, but not instructions. A simple example of this
|
|
is the ProDOS 8 call interface on the Apple II, which looks like this:</p>
|
|
<pre>
|
|
JSR $bf00
|
|
.DD1 $function
|
|
.DD2 $address
|
|
BCS BAD
|
|
</pre>
|
|
|
|
<p>The three bytes following the <code>JSR $bf00</code> should be tagged
|
|
as inline data, so that the code analyzer skips over them and continues the
|
|
analysis at the <code>BCS</code> instruction. You can think of these as
|
|
"code skip" tags, but they're different from stop/start points, because
|
|
every byte of inline data must be tagged. When
|
|
applying the tag, all bytes in a selected line will be modified.</p>
|
|
<p>If code branches into a region that is tagged as inline data, the
|
|
branch will be ignored.</p>
|
|
|
|
|
|
<h2><a name="sgconcepts">SourceGen Concepts</a></h2>
|
|
|
|
<p>As you work on a disassembled file, formatting operands and adding
|
|
comments, everything you do is saved in the project file as "meta data".
|
|
None of the data from the file being disassembled is included. This
|
|
should allow project files to be shared without violating the copyright
|
|
of the work being disassembled. (This will vary by region. Also, note
|
|
that the mere act of disassembling a piece of software may be illegal in
|
|
some cases.)</p>
|
|
|
|
<p>To avoid mix-ups where the wrong data file is used, the file's length
|
|
and CRC are stored in the project file. SourceGen will refuse to open a
|
|
project if the data file's length and CRC don't match.</p>
|
|
|
|
<p>Most of the data in the project file is associated with a file offset.
|
|
When you create a comment, you aren't associating it with line 53, you're
|
|
associating it with the 127th byte in the file. This ensures that, as the
|
|
project evolves, the comment you wrote is always connected to the
|
|
same instruction or data item. This also means you can't have two
|
|
comments on the same line -- each offset only has room for one. By
|
|
convention, file offsets are always shown as a six-digit hexadecimal value
|
|
with a leading '+', e.g. "+0012ab". This makes it easy to distinguish
|
|
between an address and a offset.</p>
|
|
|
|
<p>Instruction and data operands can be formatted in various ways. The
|
|
formatting choice is associated with the first offset of the item. For
|
|
instructions the number of bytes in the operand is determined by the opcode
|
|
(and, on the 65816, the M/X status flags). For data items the length
|
|
can be a single byte or an entire file. Operand formats are not allowed
|
|
to overlap.</p>
|
|
|
|
<p>When an instruction or data operand references an address, we call
|
|
it a <b>numeric reference</b>. When the target address has a label, and
|
|
the operand uses that symbol, we call that a <b>symbolic reference</b>.
|
|
SourceGen tries to establish symbolic references whenever possible,
|
|
so that the generated assembly source doesn't refer to hard-coded
|
|
locations within the program. Labels are generated automatically for
|
|
the targets of numeric references.</p>
|
|
|
|
<p>As your understanding of the disassembled code develops, you will want
|
|
to add comments explaining it. SourceGen projects have three kinds of
|
|
comments:</p>
|
|
<ol>
|
|
<li>End-of-line comments. As the name implies, these appear at the
|
|
end of a line, to the right of the opcode or operand.</li>
|
|
<li>Long comments, also known as multi-line comments. These get a
|
|
line all to themselves, and may span multiple lines.</li>
|
|
<li>Notes. Like long comments, these get a line to themselves. Unlike
|
|
long comments, these do not appear in generated assembly code. They
|
|
are a way for you to leave notes to yourself, perhaps "don't forget
|
|
to figure this out" or "this is the cool part".</li>
|
|
</ol>
|
|
<p>Every file offset can have one of each.</p>
|
|
|
|
<p>Labels and comments may disappear if you associate them with a file
|
|
offset that is in the middle of a multi-byte instruction or data item.
|
|
For example, suppose you put a long comment at offset +000010, and then
|
|
mark a 50-byte region starting at offset +000008 as an ASCII string. The
|
|
comment won't be deleted, but won't be displayed either. The same thing
|
|
can happen to labels. SourceGen will try to prevent this from happening
|
|
by splitting formatted data into sub-regions at label boundaries.</p>
|
|
|
|
|
|
<h2><a name="about-symbols">All About Symbols</a></h2>
|
|
|
|
<p>A symbol has two basic parts, a label and a value. The label is a short
|
|
ASCII string; the value may be an 8-to-24-bit address or a 32-bit numeric
|
|
constant. Symbols can be defined in different ways, and applied in
|
|
different ways.</p>
|
|
|
|
<p>The label syntax is restricted to a format that should be compatible
|
|
with most assemblers:</p>
|
|
<ul>
|
|
<li>2-32 characters long.</li>
|
|
<li>Starts with a letter or underscore.</li>
|
|
<li>Comprised of ASCII letters, numbers, and the underscore.</li>
|
|
</ul>
|
|
<p>Label comparisons are case-sensitive, as is customary for programming
|
|
languages.</p>
|
|
<p>Sometimes the purpose of a subroutine or variable isn't immediately
|
|
clear, but you can take a reasonable guess. You can document your
|
|
uncertainty by adding a question mark ('?') to the end of the label.
|
|
This isn't really part of the label, so it won't appear in the assembled
|
|
output, and you don't have to include it when searching for a symbol.</p>
|
|
<p>Some assemblers restrict the set of valid labels further. For example,
|
|
64tass uses a leading underscore to indicate a local label, and reserves
|
|
a double leading underscore (e.g. <code>__label</code>) for its own
|
|
purposes. In such cases, the label will be modified to comply with the
|
|
target assembler syntax.</p>
|
|
|
|
<p>Operands may use parts of symbols. For example, if you have a label
|
|
<code>MYSTRING</code>, you can write:</p>
|
|
<pre>
|
|
MYSTRING .STR "hello"
|
|
LDA #<MYSTRING
|
|
STA $00
|
|
LDA #>MYSTRING
|
|
STA $01
|
|
</pre>
|
|
<p>See <a href="#symbol-parts">Parts and Adjustments</a> for more details.</p>
|
|
|
|
<p>Symbols that represent a memory address within a project are treated
|
|
differently from those outside a project. We refer to these as internal
|
|
and external addresses, respectively.</p>
|
|
|
|
|
|
<h3><a name="connecting-operands">Connecting Operands with Labels</a></h3>
|
|
|
|
<p>Suppose you have the following code:</p>
|
|
<pre>
|
|
LDA $1234
|
|
JSR $2345
|
|
</pre>
|
|
<p>If we put that in a source file, it will assemble correctly.
|
|
However, if those addresses are part of the file, the code may break if
|
|
changes are made and things assemble to different addresses. It would
|
|
be better to generate code that references labels, e.g.:</p>
|
|
<pre>
|
|
LDA my_data
|
|
JSR nifty_func
|
|
</pre>
|
|
<p>SourceGen tries to establish labels for address operands automatically.
|
|
How this works depends on whether the operand's address is inside the file or
|
|
external, and whether there are existing labels at or near the target
|
|
address. The details are explored in the next few sections.</p>
|
|
<p>On the 65816 this process is trickier, because addresses are 24 bits
|
|
instead of 16. For a control-transfer instruction like <code>JSR</code>,
|
|
the high 8 bits come from the Program Bank Register (K). For a data-access
|
|
instruction like <code>LDA</code>, the high 8 bits come from the Data
|
|
Bank Register (B). The PBR value is determined by the address in which
|
|
the code is executing, so it's easy to determine. The DBR value can be
|
|
set arbitrarily. Sometimes it's easy to figure out, sometimes it has
|
|
to be specified manually.</p>
|
|
|
|
|
|
<h3><a name="internal-address-symbols">Internal Address Symbols</a></h3>
|
|
|
|
<p>Symbols that represent an address inside the file being disassembled
|
|
are referred to as <i>internal</i>. They come in two varieties.</p>
|
|
|
|
<p><b>User labels</b> are labels added to instructions or data by the user.
|
|
The editor will try to prevent you from creating a label that has the same
|
|
name as another symbol, but if you manage to do so, the user label takes
|
|
precedence over symbols from other sources. User labels may be tagged
|
|
as non-unique local, unique local, global, or global and exported. Local
|
|
vs. global is important for the label localizer, while exported symbols
|
|
can be pulled directly into other projects.</p>
|
|
|
|
<p><b>Auto labels</b> are automatically generated labels placed on
|
|
instructions or data offsets that are the target of operands. They're
|
|
formed by appending the hexadecimal address to the letter "L", with
|
|
additional characters added if some other symbol has already defined
|
|
that label. Options can be set that change the "L" to a character or
|
|
characters based on how the label is referenced, e.g. "B" for branch targets.
|
|
Auto labels are only added where they are needed, and are removed when
|
|
no longer necessary. Because auto labels may be renamed or vanish, the
|
|
editor will try to prevent you from referring to them explicitly when
|
|
editing operands.</p>
|
|
|
|
|
|
<h3><a name="external-address-symbols">External Address Symbols</a></h3>
|
|
|
|
<p>Symbols that represent an address outside the file being disassembled
|
|
are referred to as <i>external</i>. These may be ROM entry points,
|
|
data buffers, zero-page variables, or a number of other things. Because
|
|
the memory address they appear at aren't within the bounds of the file,
|
|
we can't simply put an address label on them. Three different mechanisms
|
|
exist for defining them. If an instruction or data operand refers to
|
|
an address outside the file bounds, SourceGen looks for a symbol with
|
|
a matching address value.</p>
|
|
|
|
<p><b>Platform symbols</b> are defined in platform symbol files. These
|
|
are named with a ".sym65" extension, and have a fairly straightforward
|
|
name/value syntax. Several files for popular platforms come with SourceGen
|
|
and live in the <code>RuntimeData</code> directory. You can also create your
|
|
own, but they have to live in the same directory as the project file.</p>
|
|
|
|
<p>Platform symbols can be addresses or constants. Addresses are
|
|
limited to 24-bit values, and are matched automatically. Constants may
|
|
be 32-bit values, but must be specified manually.</p>
|
|
|
|
<p>If two platform symbols have the same label, only the most recently read
|
|
one is kept. If two platform symbols have different labels but the
|
|
same value, both symbols will be kept, but the one in the file loaded
|
|
last will take priority when doing a lookup by address. If symbols with
|
|
the same value are defined in the same file, the one whose symbol appears
|
|
first alphabetically takes priority.</p>
|
|
|
|
<p>Platform address symbols have an optional width. This can be used
|
|
to define multi-byte items, such as two-byte pointers or 256-byte stacks.
|
|
If no width is specified, a default value of 1 is used. Widths are ignored
|
|
for constants.
|
|
Overlapping symbols are resolved as described earlier, with symbols loaded
|
|
later taking priority over previously-loaded symbols. In addition,
|
|
symbols defined closer to the target address take priority, so if you put
|
|
a 4-byte symbol in the middle of a 256-byte symbol, the 4-byte symbol will
|
|
be visible because the start point is closer to the addresses it covers
|
|
than the start of the 256-byte range.</p>
|
|
|
|
<p>Platform symbols can be designated for reading, writing, or both.
|
|
Normally you'd want both, but if an address is a memory-mapped I/O
|
|
location that has different behavior for reads and writes, you'd want
|
|
to define two different symbols, and have the correct one applied
|
|
based on the access type.</p>
|
|
|
|
<p><b>Project symbols</b> behave like platform symbols, but they are
|
|
defined in the project file itself, through the Project Properties editor.
|
|
The editor will try to prevent you from creating two symbols with the same
|
|
name. If two symbols have the same value, the one whose label comes
|
|
first alphabetically is used.</p>
|
|
|
|
<p>Project symbols always have precedence over platform symbols, allowing
|
|
you to redefine symbols within a project. (You can "hide" a platform
|
|
symbol by creating a project symbol constant with the same name. Use a
|
|
value like $ffffffff or $deadbeef so you'll know why it's there.)</p>
|
|
|
|
<p><b>Local variables</b> are redefinable symbols that are organized
|
|
into tables. They're used to specify labels for zero-page addresses
|
|
and 65816 stack-relative instructions. These are explained in more
|
|
detail in the next section.</p>
|
|
|
|
|
|
<h4><a name="local-vars">How Local Variables Work</a></h4>
|
|
|
|
<p>Local variables are applied to instructions that have zero
|
|
page operands (<code>op ZP</code>, <code>op (ZP),Y</code>, etc.), or
|
|
65816 stack relative operands
|
|
(<code>op OFF,S</code> or <code>op (OFF,S),Y</code>). While they must be
|
|
unique relative to other kinds of labels, they don't have to be unique
|
|
with respect to earlier variable definitions. So you can define
|
|
<code>TMP .EQ $10</code>, and a few lines later define
|
|
<code>TMP .EQ $20</code>. This is handy because zero-page addresses are
|
|
often used in different ways by different parts of the program. For
|
|
example:</p>
|
|
<pre>
|
|
LDA ($00),Y
|
|
INC $02
|
|
... elsewhere ...
|
|
DEC $00
|
|
STA ($01),Y
|
|
</pre>
|
|
<p>If we had given <code>$00</code> the label <code>PTR</code> and
|
|
<code>$02</code> the label <code>COUNT</code> globally,
|
|
the second pair of instructions would look all wrong. With local
|
|
variable tables you can set <code>PTR=$00 COUNT=$02</code> for the first chunk,
|
|
and <code>COUNT=$00 PTR=$01</code> for the second chunk.</p>
|
|
|
|
<p>Local variables have a value and a width. If we create a pair of
|
|
variable definitions like this:</p>
|
|
<pre>
|
|
PTR .eq $00 ;2 bytes
|
|
COUNT .eq $02 ;1 byte
|
|
</pre>
|
|
<p>Then this:</p>
|
|
<pre>
|
|
STA $00
|
|
STX $01
|
|
LDY $02
|
|
</pre>
|
|
<p>Would become:</p>
|
|
<pre>
|
|
STA PTR
|
|
STX PTR+1
|
|
LDY COUNT
|
|
</pre>
|
|
|
|
<p>The scope of a variable definition starts at the point where it is
|
|
defined, and stops when its definition is erased. There are three
|
|
ways for a table to erase an earlier definition:</p>
|
|
<ol>
|
|
<li>Create a new definition with the same name.</li>
|
|
<li>Create a new definition that has an overlapping value. For
|
|
example, if you have a two-byte variable <code>PTR = $00</code>,
|
|
and define a one-byte variable <code>COUNT = $01</code>, the
|
|
definition for <code>PTR</code> will be cleared because its second
|
|
byte overlaps.</li>
|
|
<li>Tables have a "clear previous" flag that erases all previous
|
|
definitions. This doesn't usually cause anything to be generated in the
|
|
assembly sources; instead, it just causes SourceGen to stop using
|
|
that label.</li>
|
|
</ol>
|
|
<p>As you might expect, you're not allowed to have duplicate labels or
|
|
overlapping values in an individual table.</p>
|
|
<p>If a platform/project symbol has the same value as a local variable,
|
|
the local variable is used. If the local variable definition is cleared,
|
|
use of the platform/project symbol will resume.</p>
|
|
<p>Not all assemblers support redefinable variables. In those cases,
|
|
the symbol names will be modified to be unique (e.g. the second definition
|
|
of <code>PTR</code> becomes <code>PTR_1</code>), and variables will have
|
|
global scope.</p>
|
|
|
|
|
|
<h3><a name="unique-local-global">Unique vs. Non-Unique and Local vs. Global</a></h3>
|
|
|
|
<p>Most assemblers have a notion of "local" labels, which have a scope
|
|
that is book-ended by global labels. These are handy for generic branch
|
|
target names like "loop" or "notzero" that you might want to use in
|
|
multiple places. The exact definition of local variable scope varies
|
|
between assemblers, so labels that you want to be local might have to
|
|
be promoted to global (and probably renamed).</p>
|
|
<p>SourceGen has a similar concept with a slight twist: they're called
|
|
non-unique labels, because the goal is to be able to use the same
|
|
label in more than one place. Whether or not they actually turn out
|
|
to be local is a decision deferred to assembly source generation time.
|
|
(You can also declare a label to be a unique local if you like; the
|
|
auto-generated labels like "L1234" do this.)</p>
|
|
<p>When you're writing code for an assembler, it has to be unambiguous,
|
|
because the assembler can't guess at what the output should be. For a
|
|
disassembler, the output is known, so a greater degree of ambiguity is
|
|
tolerable. Instead of throwing errors and refusing to continue, the
|
|
source generator can modify the output until it works. For example:<p>
|
|
<pre>
|
|
@LOOP LDX #$02
|
|
@LOOP DEX
|
|
BNE @LOOP
|
|
DEY
|
|
BNE @LOOP
|
|
</pre>
|
|
<p>This would confuse an assembler. SourceGen already knows which @LOOP
|
|
is being branched to, so it can just rename one of them to "@LOOP1".</p>
|
|
<p>One situation where non-unique labels cause difficulty is with
|
|
weak symbolic references (see next section). For example, suppose
|
|
the above code then did this:</p>
|
|
<pre>
|
|
LDA #<@LOOP
|
|
</pre>
|
|
<p>While it's possible to make an educated guess at which @LOOP was
|
|
meant, it's easy to get wrong. In situations like this, it's best to
|
|
give the labels different names.</p>
|
|
|
|
|
|
<h3><a name="weak-refs">Weak Symbolic References</a></h3>
|
|
|
|
<p>Symbolic references in operands are "weak references". If the named
|
|
symbol exists, the reference is used. If the symbol can't be found, the
|
|
operand is formatted in hex instead. They're called "weak" because
|
|
failing to resolve the reference isn't considered an error.</p>
|
|
|
|
<p>It's important to know this when editing a project. Consider the
|
|
following trivial chunk of code:</p>
|
|
|
|
<pre>
|
|
1000: 4c0310 JMP $1003
|
|
1003: ea NOP
|
|
</pre>
|
|
|
|
<p>When you load it into SourceGen, it will be formatted like this:</p>
|
|
<pre>
|
|
.ORG $1000
|
|
JMP L1003
|
|
L1003 NOP
|
|
</pre>
|
|
|
|
<p>The analyzer found the JMP operand, and created an auto label for
|
|
address $1003. It then created a weak reference to "L1003" in the JMP
|
|
operand.</p>
|
|
|
|
<p>If you edit the JMP instruction's operand to use the symbol "FOO", the
|
|
results are probably not what you want:</p>
|
|
<pre>
|
|
.ORG $1000
|
|
JMP $1003
|
|
NOP
|
|
</pre>
|
|
|
|
<p>This happened because you added a weak reference to "FOO" in the operand,
|
|
but the label doesn't exist. The operand is formatted as hex. Because
|
|
there's no longer a reference to L1003, SourceGen removed the auto-label
|
|
as well.</p>
|
|
|
|
<p>If you set the label "FOO" on the NOP instruction, you'll see what you
|
|
probably wanted:</p>
|
|
<pre>
|
|
.ORG $1000
|
|
JMP FOO
|
|
FOO NOP
|
|
</pre>
|
|
|
|
<p>You don't actually need the explicit reference in the JMP instruction.
|
|
If you edit the JMP operand and set it back to "Default", the code will
|
|
still look the same. This is because SourceGen identified the numeric
|
|
reference, and automatically added a symbolic reference to the label on
|
|
the NOP instruction.</p>
|
|
|
|
<p>However, suppose you didn't actually want FOO as the operand label.
|
|
You can create a project symbol, BAR with the value $1003, and then edit
|
|
the operand to reference BAR instead. Your code would then look like:</p>
|
|
<pre>
|
|
BAR .EQ $1003
|
|
.ORG $1000
|
|
JMP BAR
|
|
FOO NOP
|
|
</pre>
|
|
|
|
<p>If you change the value of BAR in the project symbol file, the operand
|
|
will continue to refer to it, but with an adjustment. For example, if
|
|
you changed BAR from $1003 to $1007, the code would become:</p>
|
|
<pre>
|
|
BAR .EQ $1007
|
|
.ORG $1000
|
|
JMP BAR-4
|
|
FOO NOP
|
|
</pre>
|
|
|
|
<p>If you rename a label, all references to that label are updated. For
|
|
numeric references that happens implicitly. For explicit operand
|
|
references, the weak references are updated individually. (Modern IDEs
|
|
call this "refactoring".)</p>
|
|
<p>If you remove a label, all of the numeric references to it will
|
|
reference something else, probably a new auto label. Weak references
|
|
to the symbol will break and be formatted as hex, but will not be
|
|
removed. Similarly, removing symbols from a platform or project file
|
|
will break the reference but won't modify the operands.</p>
|
|
|
|
<h3><a name="symbol-parts">Parts and Adjustments</a></h3>
|
|
|
|
<p>Sometimes you want to use part of a label, or adjust the value slightly.
|
|
(I use "adjustment" rather than "offset" to avoid confusing it with file
|
|
offsets.) Consider the following example:</p>
|
|
<pre>
|
|
1000: a910 LDA #$10
|
|
1002: 48 PHA
|
|
1003: a906 LDA #$06
|
|
1005: 48 PHA
|
|
1006: 60 RTS
|
|
1007: 4c3aff JMP $ff3a
|
|
</pre>
|
|
|
|
<p>This pushes the address of the JMP instruction ($1007) onto the stack,
|
|
and jumps to it with the RTS instruction. However, RTS requires the
|
|
address of the byte before the target instruction, so we actually push
|
|
$1006.</p>
|
|
|
|
<p>The disassembler won't know that offset $1007 is code because nothing
|
|
appears to reference it. After tagging $1007 as a code start point, the
|
|
project looks like this:</p>
|
|
<pre>
|
|
LDA #$10
|
|
PHA
|
|
LDA #$06
|
|
PHA
|
|
RTS
|
|
|
|
JMP $ff3a
|
|
</pre>
|
|
|
|
<p>We set a label called "NEXT" on the JMP instruction, and then edit
|
|
the two LDA instructions to reference the high and low parts, yielding:</p>
|
|
<pre>
|
|
.ORG $1000
|
|
LDA #>NEXT
|
|
PHA
|
|
LDA #<NEXT-1
|
|
PHA
|
|
RTS
|
|
|
|
NEXT JMP $ff3a
|
|
</pre>
|
|
|
|
<p>SourceGen will adjust label values by whatever amount is required to
|
|
generate the original value. If the adjustment seems wrong, make sure
|
|
you're selecting the right part of the symbol.</p>
|
|
|
|
<p>Different assemblers use different syntaxes to form expressions. This
|
|
is particularly noticeable in 65816 code. You can adjust how it appears
|
|
on-screen from the app settings.</p>
|
|
|
|
<h3><a name="nearby-targets">Automatic Use of Nearby Targets</a></h3>
|
|
|
|
<p>Sometimes you want to use a symbol that doesn't match up with the
|
|
operand. SourceGen tries to anticipate situations where that might be
|
|
the case, and apply adjustments for you.</p>
|
|
|
|
<p>Suppose you have the following:</p>
|
|
<pre>
|
|
.ORG $1000
|
|
LDA #$00
|
|
STA L1010
|
|
LDA #$20
|
|
STA L1011
|
|
LDA #$e1
|
|
STA L1012
|
|
RTS
|
|
|
|
L1010 .DD1 $00
|
|
L1011 .DD1 $00
|
|
L1012 .DD1 $00
|
|
</pre>
|
|
|
|
<p>Showing stores to three different labeled addresses is fine, but
|
|
the code is actually setting up a single 24-bit address. For clarity,
|
|
you'd like the output to reflect the fact that it's a single, multi-byte
|
|
variable. So, if you set a label at $1010, SourceGen removes the
|
|
nearby auto labels, and sets the numeric references to use your label:</p>
|
|
|
|
<pre>
|
|
.ORG $1000
|
|
LDA #$00
|
|
STA DATA
|
|
LDA #$20
|
|
STA DATA+1
|
|
LDA #$e1
|
|
STA DATA+2
|
|
RTS
|
|
|
|
DATA .DD1 $00
|
|
.DD1 $00
|
|
.DD1 $00
|
|
</pre>
|
|
|
|
<p>If you decide that you really wanted each store to have its own
|
|
label, you can set labels on the other two addresses. SourceGen won't
|
|
search for alternate labels if the numeric reference target has a
|
|
user-defined label.</p>
|
|
|
|
<p>This is also used for self-modifying code. For example:</p>
|
|
<pre>
|
|
1000: a9ff LDA #$ff
|
|
1002: 8d0610 STA $1006
|
|
1005: 4900 EOR #$00
|
|
</pre>
|
|
|
|
<p>The above changes the <code>EOR #$00</code> instruction to
|
|
<code>EOR #$ff</code>. The operand target is $1006, but we can't
|
|
put a label there because it's in the middle of the instruction. So
|
|
SourceGen puts a label at $1005 and adjusts it:</p>
|
|
<pre>
|
|
LDA #$ff
|
|
STA L1005+1
|
|
L1005 EOR #$00
|
|
</pre>
|
|
|
|
<p>If you really don't like the way this works, you can disable the
|
|
search for nearby targets entirely from the
|
|
<a href="settings.html#project-properties">project properties</a>.
|
|
Self-modifying code will always be adjusted because of the limitation
|
|
on mid-instruction labels.</p>
|
|
|
|
|
|
<h2><a name="width-disambiguation">Width Disambiguation</a></h2>
|
|
|
|
<p>It's possible to interpret certain instructions in multiple ways.
|
|
For example, "LDA $0000" might be an absolute load from a 16-bit
|
|
address, or it might be a direct page load from an 8-bit address.
|
|
Humans can infer from the fact that it was written with a 4-digit address
|
|
that it's meant to be absolute, but assemblers often treat operands
|
|
purely as numbers, and would just see "LDA 0". Common practice is to
|
|
use the shortest instruction possible.</p>
|
|
<p>Every assembler seems to address the problem in a slightly different
|
|
way. Some use opcode suffixes, others use operand prefixes, some
|
|
allow both. You can configure how they appear in the
|
|
<a href="settings.html#app-settings">application settings</a>.</p>
|
|
<p>SourceGen will only add width disambiguators to opcodes or operands when
|
|
they are needed, with one exception: the opcode suffix for long
|
|
(24-bit address) operations is always applied. This is done because some
|
|
assemblers require it, insisting on "LDAL" rather than "LDA" for an
|
|
absolute long load, and because it can make 65816 code easier to read.</p>
|
|
|
|
|
|
<h2><a name="pseudo-ops">Data and Directive Pseudo-Opcodes</a></h2>
|
|
|
|
<p>The on-screen code list shows assembler directives that are similar
|
|
to what the various cross-assemblers provide. The actual directives
|
|
generated for a given assembler may match exactly or be totally different.
|
|
The idea is to represent the concept behind the directive, then let the
|
|
code generator figure out the implementation details.</p>
|
|
|
|
<p>There are six assembler directives that appear in the code list:</p>
|
|
<ul>
|
|
<li>.EQ - defines a symbol's value. These are generated automatically
|
|
when an operand that matches a platform or project symbol is found.</li>
|
|
<li>.VAR - defines a local variable. These are generated for
|
|
local variable tables.</li>
|
|
<li>.ORG - changes the target address.</li>
|
|
<li>.RWID - specifies the width of the accumulator and index registers
|
|
(65816 only). Note this doesn't change the actual width, just tells
|
|
the assembler that the width has changed.</li>
|
|
<li>.DBANK - specifies what value the Data Bank Register holds
|
|
(65816 only). Used when matching operands to labels.</li>
|
|
<li>.JUNK - indicates that the data in a range of bytes is irrelevant.
|
|
(When generating sources, this will become .FILL or .BULK
|
|
depending on the contents of the memory region and the assembler's
|
|
capabilities.)</li>
|
|
<li>.ALIGN - a special case of .JUNK that indicates the irrelevant
|
|
bytes exist to force alignment to a memory boundary (usually a
|
|
256-byte page). Depending on the memory contents, it may be possible
|
|
to output this as an assembler-specific alignment directive.</li>
|
|
</ul>
|
|
|
|
<p>Every data item is represented by a pseudo-op. Some of them may
|
|
represent hundreds of bytes and span multiple lines.</p>
|
|
<ul>
|
|
<li>.DD1, .DD2, .DD3, .DD4 - basic "define data" op. A 1-4 byte
|
|
little-endian value.</li>
|
|
<li>.DBD2, .DBD3, .DBD4 - "define big-endian data". 2-4 bytes of
|
|
big-endian data. (The 3- and 4-byte versions are not currently
|
|
available in the UI, since they're very unusual and few assemblers
|
|
support them.)</li>
|
|
<li>.BULK - data packed in as compact a form as the assembler allows.
|
|
Useful for chunks of graphics data.</li>
|
|
<li>.FILL - a series of identical bytes. The operand
|
|
has two parts, the byte count followed by the byte value.</li>
|
|
</ul>
|
|
|
|
<p>In addition, several pseudo-ops are defined for string constants:</p>
|
|
<ul>
|
|
<li>.STR - basic character string.</li>
|
|
<li>.RSTR - string in reverse order.</li>
|
|
<li>.ZSTR - null-terminated string.</li>
|
|
<li>.DSTR - Dextral Character Inverted string. The high bit of the
|
|
last byte is flipped.</li>
|
|
<li>.L1STR - string prefixed with a length byte.</li>
|
|
<li>.L2STR - string prefixed with a length word.</li>
|
|
</ul>
|
|
|
|
<p>You can configure the pseudo-operands to look more like what your
|
|
favorite assembler uses in the
|
|
<a href="settings.html#appset-pseudoop">Pseudo-Op</a> tab in the
|
|
application settings.</p>
|
|
|
|
<p>String constants start and end with delimiter characters, typically
|
|
single or double quotes. You can configure the delimiters differently
|
|
for each character encoding, so that it's obvious whether the text is
|
|
in ASCII or PETSCII. See the
|
|
<a href="settings.html#appset-textdelim">Text Delimiters</a> tab in
|
|
the application settings.</p>
|
|
|
|
|
|
</div>
|
|
|
|
<div id="footer">
|
|
<p><a href="index.html">Back to index</a></p>
|
|
</div>
|
|
</body>
|
|
<!-- Copyright 2018 faddenSoft -->
|
|
</html>
|