It's fairly common to want to Find something and then jump back to
where you were. The Find command now adds the current position to
the nav stack for the initial search. If you Find Next, the nav
stack is not altered.
This experimental feature applied platform symbols to the project,
setting labels where the platform symbol's address matched an internal
address. The feature now applies project symbols as well, and has
been renamed to "apply external symbols".
We now report the number of labels set.
First, make the per-segment comments and notes optional.
Second, add an "offset segment by $0100" feature that tries to shift
each segment forward 256 bytes. Doing so avoids potential ambiguity
with direct page locations.
The 20212-reloc-data test no longer has the per-segment comments.
The "smart" PLP handler tries to recover the flags from an earlier
PHP. The non-smart version just marks all the flags as indeterminate.
This doesn't work well on the 65816 in native mode, because having
the M/X flags in an indeterminate state is rarely what you want.
Code rarely uses PLP to reset the flags to a specific state, preferring
explicit SEP/REP. The analyzer is more likely to get the correct
answer by simply leaving the flags in their prior state.
A test case has been added to 20052-branches-and-banks, which now has
"smart PLP" disabled.
Long operands, such as strings and bulk data, can span multiple lines.
SourceGen wraps them at 64 characters, which is fine for assembly
output but occasionally annoying on screen: if the operand column is
wide enough to show the entire value, the comment column is pushed
pretty far to the right.
This change makes the width configurable, as 32/48/64 characters,
with a pop-up in app settings.
The assemblers are all wired to 64 characters, though we could make
this configurable as well with an assembler-specific setting.
Some things have moved around a bit in app settings. The Asm Config
tab now comes last. Having it sandwiched in the middle of tabs that
altered the on-screen display didn't make much sense. The Display
Format is now explicitly for opcodes and operands, and is split into
two columns. The left column is managed by the "quick set" feature,
the right column is independent.
Another chapter in the never-ending AppDomain security saga.
If a computer goes to sleep while SourceGen is running with a project
open, life gets confusing when the system wakes up. The keep-alive
timer fires and a ping is sent to the remote AppDomain, successfully.
At the same time, the lease expires on the remote side, and the objects
are discarded (apparently without bothering to query the ILease object).
This failure mode is 100% repeatable.
Since we can't prevent sandbox objects from disappearing, we have to
detect and recover from the problem. Fortunately we don't keep any
necessary state on the plugin side, so we can just tear the whole
thing down and recreate it.
The various methods in ScriptManager now do a "health check" before
making calls into the plugin AppDomain. If the ping attempt fails,
the AppDomain is "rebooted" by destroying it and creating a new one,
reloading all plugins that were in there before. The plugin binaries
*should* still be in the PluginDllCache directory since the ping failure
was due to objects being discarded, not AppDomain shutdown, and Windows
doesn't let you mess with files that hold executable code.
A new "reboot security sandbox" option has been added to the DEBUG
menu to facilitate testing.
The PluginManager's Ping() method gets called more often, but not to
the extent that performance will be affected.
This change also adds a finalizer to DisasmProject, since we're relying
on it to shut down the ScriptManager, and it's relying on callers to
invoke its cleanup function. The finalizer throws an assertion if the
cleanup function doesn't get called.
(Issue #82)
Changed "Use Keep-Alive Hack" to "Disable Keep-Alive Hack" to emphasize
that it defaults to enabled. Added a menu item for "Disable Security
Sandbox". Added a warning to both that tells the user that they must
reopen the current project for the change to take effect.
Note neither of these is persisted in app settings.
When formatting a table of 16-bit addresses in 65816 code, the bank
byte was always being set to zero. However, for "JMP (addr,X)", the
program bank is used. We now default to that behavior.
The choice can be overridden as before (select 24-bit addresses with a
constant value for the bank byte).
The old values were pretty optimistic in terms of the length of labels.
Short labels in all caps are very retro but sort of annoying to read,
so most disassemblies use longer ones. The new defaults are more
accommodating for the way labels are actually used.
The new name is more indicative of the purpose of the directory.
Updated the docs to point out that you can delete the contents any
time you want, so long as SourceGen isn't running at the time.
Also, change the default column widths for the exporter.
Don't allow comments to be set in the middle of an instruction or
multi-byte data item. The subsequent partial update confuses the
line list generator.
Change order of note/long-comment/comment to match display.
Expand SGEC to include long comments and notes. These are serialized
in JavaScript form.
SGEC now accepts addresses and relative position deltas. Exported
content uses addresses, and can be configured for deltas.
This is still an "experimental" feature, but it's getting expanded
a bit. The implementation now lives in its own class. An "export"
feature that generates SGEC data has been added. The file extension
has been changed from ".sgec" to ".txt" to make it simpler to edit
under Windows.
On an Apple IIgs, the memory-mapped I/O locations are actually in
bank $e0, shadow-copied to bank $00. This adds a copy of the
relevant definitions from Cxxx-IO.sym65, with the addresses in bank
$e0 and "_GS" appended to the labels.
This is now included by default for the Apple IIgs system defintions.
(I thought about just adding them to Cxxx-IO.sym65, but then they
pollute the namespace for 8-bit systems. Stripping them out at run
time got a little complicated because the platform symbols are only
loaded once, and we'd have to reload them every time the CPU definition
changed. Further, there are a few aliases provided as constants, and
constants are allowed to be 32 bits on all systems, so those can't be
stripped. Rather than defining a new definition I figured it was
just easier to have a second file. Maintenance shouldn't be too taxing,
as definitions for 40-year-old machines don't change all that often.)
(I also thought about trying to make the address mirroring stuff work
for me here, but that would result in accesses being made to the
canonical address with an offset of +$e00000, which looks awful.)
The Disk ][ I/O locations are generally accessed as an offset, using
something like "LDA $C08n,X". However the range from $C080-C08F is
already used for language card in slot 0. SourceGen doesn't have a
way to distinguish between indexed and direct accesses, and even if
it did there's no way to separate one peripheral card from another
without knowing the contents of the CPU register.
As a workaround, the Disk ][ definitions are now in a separate symbol
file. When loaded, the definitions replace the base slot 0 equates.
I figure Disk ][ accesses are more common than language card
manipulation, so I'm making it a default for new projects. Existing
projects that reference the Disk ][ symbols (which existed, but as
constants) will need to be updated to include the new .sym65.
When we have relocation data available, the code currently skips the
process of matching an address with a label for a PEA instruction when
the instruction in question doesn't have reloc data. This does a
great job of separating code that pushes parts of addresses from code
that pushes constants.
This change expands the behavior to exclude instructions with 16-bit
address operands that use the Data Bank Register, e.g. "LDA abs"
and "LDA abs,X". This is particularly useful for code that accesses
structured data using the operand as the structure offset, e.g.
"LDX addr" / "LDA $0000,X"
The 20212-reloc-data test has been updated to check the behavior.
Add 20222-data-bank to regression test suite. This exercises handling
of 16-bit operands with inter- and intra-bank references, and tests the
smartness in "smart PLB".
Also, update a couple of older tests that broke because the DBR is no
longer always the same as the PBR. This just required adding "B=K"
in a few places to restore the original output.
If code accesses the high/low parts of a 32-bit address value with
no label, it auto-generates labels for addr+2 and addr. The reloc
handler was replacing the unformatted bytes with a single multi-byte
format, hiding the label at addr+2.
The easy fix is to have the reloc data handler skip the entry. This
is less useful than other approaches, but much simpler.
Added a test to 20212-reloc-data.
Implemented "smart" PLB handling. If we see PHK/PLB, or 8-bit
LDA imm/PHA/PLB, we create a data bank change item. The feature
can be disabled with a project property.
Added a "fake" assembler pseudo-op for DBR changes. Display entries
in line list.
Added entry to double-click handler so that you can double-click on
a PLB instruction operand to open the data bank editor.
Changed basic data item from an "extended enum" to a class, so we can
keep track of where things come from (useful for the display list).
Finished edit dialog. Added serialization to project file.
On the 65816, 16-bit data access instructions (e.g. LDA abs) are
expanded to 24 bits by merging in the Data Bank Register (B). The
value of the register is difficult to determine via static analysis,
so we need a way to annotate the disassembly with the correct value.
Without this, the mapping of address to file offset will sometimes
be incorrect.
This change adds the basic data structures and "fixup" function, a
functional but incomplete editor, and source for a new test case.
The Visual Studio performance profiler showed the FormatDescriptor
equality test being called quite a lot. The test was vs. null, so
a simple change from "==" to "is" improved performance dramatically.
Fixing the underlying issue with a better data structure is still
important, but this provided a big boost with little effort.
The test wasn't correctly excluding instructions, so it was possible
to create a situation where a two-byte data item had an instruction
starting in the second byte.
We also weren't checking the length of the instruction to ensure that
it was wider than the reloc data. This could get weird for an
immediate constant when the M/X flags are wrong. When in doubt, don't
overwrite.
The decision of how to handle indeterminate M/X flag values is made in
StatusFlags. This provides consistent behavior throughout the app.
This was being done for M/X but not for E.
This change also renames the M/X tests, prefixing them with "Is" to
emphasize that they are boolean rather than tri-state.
There should be no change in behavior from this.
This test exercises the relocation data feature. The test file is
generated from a multi-segment OMF file that was hex-edited to have
specific attributes (see 20212-reloc-data-lnk.S for instructions).
The test also serves as a way to exercise the OMF converter.
Also, implement the Bank Relative flag.
The Absolute Indirect and Absolute Indirect Long addressing modes
(e.g. "JMP (addr)" and "JMP [addr]") are 16-bit values in bank 0.
The code analyzer was placing them in the program bank, which
meant the wrong symbol was being used.
Also, tweak some docs.
Works well for things like jump tables. Seeing a bunch of these
scattered in a chunk of data is a decent signal that it's actually
code.
In a bold move, we now exclude PEA operands from auto-label gen when
they don't have relocation data. This is very useful for things
like Int2Hex for which constants are typically pushed with PEA.
Reworked the "use reloc data" setting so it defaults to false and is
explicitly set to true when converting OMF. This provides a minor
optimization since we now check the boolean and skip doing a lookup
in an empty table.
Similar to the ProDOS 8 formatter, but slightly more complex due
to the variable-length parameter block layout.
Also, added Orca shell call numbers to the list of constants.
This was a relatively lightweight change to confirm the usefulness
of relocation data. The results were very positive.
The relatively superficial integration of the data into the data
analysis process causes some problems, e.g. the cross-reference table
entries show an offset because the code analyzer's computed operand
offset doesn't match the value of the label. The feature should be
considered experimental
The feature can be enabled or disabled with a project property. The
results were sufficiently useful and non-annoying to make the setting
enabled by default.
Code generated for 64tass was incorrect for JSR/JMP to a location
outside the file bounds. A test added to 20052-branches-and-banks
revealed an issue with cc65 generation as well.
A "cooked" form of the relocation data is added to the project, for
use during data analysis.
Also, changed the data grids in the segment viewer to allow multi-
select, so users can copy & paste the contents.
We now put a code hint on the JML instruction in each jump table
entry. This is necessary to ensure that the target address is
recognized as code, since a dynamic segment won't otherwise be
referenced.
Also, fiddle with the note/comment formatting some more.
Two basic problems:
(1) cc65, being a one-pass assembler, can't tell if a forward-referenced
label is 16-bit or 24-bit. If the operand is potentially ambiguous,
such as "LDA label", we need to add an operand width disambiguator.
(The existing tests managed to only do backward references.)
(2) 64tass wants the labels on JMP/JSR absolute operands to have 24-bit
values that match the current program bank. This is the opposite of
cc65, which requires 16-bit values. We need to distinguish PBR vs.
DBR instructions (i.e. "LDA abs" vs. "JMP abs") and handle them
differently when formatting for "Common".
Merlin32 doesn't care, and ACME doesn't work at all, so neither of
those needed updating.
The 20052-branches-and-banks test was expanded to cover the problematic
cases.
The handful of 6502-based Atari coin-op systems were very different
from each other, so having a dedicated entry doesn't make sense.
Also, enable word-wrap in the New Project text box that holds the
system description.
The GS/OS loader initializes the calls with JSLs to a loader entry
point, and replaces them with JMLs to code in dynamic segments when
the segments are loaded. Since we have all the segments loaded at
once, we can just rewrite them to be JMLs immediately.
Changed bank-start comments to notes, added a summary to the top-of-file
comment.
Also, fixed a bug where the app settings dialog wasn't identifying
display settings as a preset for 64tass and cc65.
Generate multiple .ORG directives for segments that span multiple
banks. Some assemblers don't like it when things cross. This is
pretty rare (Cryllan Mission is an example).
Conversion of OMF Load files to a data/project pair is generally
working. The 65816 source code generators need some work though.
Added generation of the relocation dictionary and constant body for
segments in Load files.
Also, don't reject files with v1 segments (whose length is specified
as a block count) just because the EOF isn't a multiple of 512 bytes.
Some executables don't pad out the last block.
Various tweaks to output formatting.
Added file type determination (Load, Object, Library). Requires
screening the segment and record types.
Also, fix parsing of v0 headers, which placed ORG and ALIGN in
different places.
Added generation of info/error messages to segment parser, which
are displayed in the main OMF viewer window.
Added segment viewer window, which opens when a segment entry in the
viewer list is double-clicked. Currently shows the "raw" header
fields, with place-holder UI for additional stuff.
It's nice to be able to save images from the visualization editor
for display elsewhere. This can be done during HTML export, but
that's inconvenient when you just want one image, and doesn't allow
the output size to be specified.
This change adds an Export button to the Edit Visualization dialog.
The current bitmap, wireframe, or wireframe animation can be saved
to a GIF image. A handful of sizes can be selected from a pop-up
menu.
My original goal was to add a sign-extended decimal format, but that
turned out to be awkward. It works for data items and instructions
with immediate operands (e.g. "LDA #-1"), but is either wrong or
useless for address operands, since most assemblers treat integers
as 32-bit values. (LDA -1 is not LDA $FFFF, it's LDA $FFFFFFFF,
which is not useful unless your asm is doing an implicit mod.)
There's also a bit of variability in how assemblers treat negative
values, so I'm shelving the idea for now. I'm keeping the updated
tests, which are now split into 6502 / 65816 parts.
Also, updated the formatter to output all decimal values as unsigned.
Most assemblers were fine with negative values, but 64tass .dword
insists on positive. Rather than make the opcode conditional on the
value's range, we now just always output unsigned decimal, which
all current assemblers accept.
If you double-click on the opcode of an instruction whose operand is
an address or equate, the selection jumps to that address. This
feature is now available in the Navigate menu, with the keyboard
shortcut Ctrl+J.
While testing the feature I noticed that the keyboard focus wasn't
following the selection, so if you jumped to an address and then
used the up/down arrows, you jumped back to the previous location.
(This was true when double-clicking an opcode to jump; it was just
less noticeable since the next action was likely mouse-based.) This
has been fixed by updating the ListView item focus when we jump to a
new location.
See also issue #63 and issue #72.
Add a 6502-only version of the 20032-labels-and-symbols test. The
65816 version could get away with just the 65816-specific stuff, but
there's no real need to modify it. (The next time I update it I may
remove the duplicate label since that requires hand-editing.)
The regression tests were written with the assumption that all cross
assemblers would support 6502, 65C02, and 65816 code. There are a
few that support 65816 partially (e.g. ACME) or not at all. To best
support these, we need to split some of the tests into pieces, so
that important 6502 tests aren't skipped simply because parts of the
test also exercise 65816 code.
The first step is to change the regression test naming scheme. The
old system used 1xxx for tests without project files, and 2xxx for
tests with project files. The new system uses 1xxxN / 2xxxN, where
N indicates the CPU type: 0 for 6502, 1 for 65C02, and 2 for 65816.
For the 1xxxN tests the new value determines which CPU is used,
which allows us to move the "allops" 6502/65C02 tests into the
no-project category. For 2xxxN it just allows the 6502 and 65816
versions to have the same base name and number.
This change updates the first batch of tests. It involves minor
changes to the test harness and a whole bunch of renaming.
ACME has a "real" PC and a "pseudo" PC. The "real" PC determines the
initial position in a 64KB buffer used to hold assembler output. If
the amount of code generated runs off the end, the assembler fails
with "produced too much code".
The source code generator in SourceGen was outputting a "real" PC
for the first address range and "psuedo" PCs for any address ranges
that followed. This produced nice results for code with a single
range, but caused problems for multi-range sources if the initial
range was high in memory and a later range was lower in memory.
While the assembler isn't actually generating more than 64KB of code,
ACME's buffer management was detecting an overflow.
Now, if a source file has multiple address ranges, we set the "real"
PC to $0000 and use a "pseudo" PC for all ranges. Output for projects
with a single address range is unmodified.
Added a visualizer for the CHR ROM pattern tables, and a semi-useful
visualizer for tile grids.
Also added a few chars in an 8x8 font that visualizers can use to
label things.
JSR/JSL calls with inline data have the option of reporting that
they don't continue, which causes the code analyzer to treat them
as JMPs instead. There was a bug that was causing the no-continue
flag to be lost in certain circumstances.
The code now explicitly records the plugin's response in an Anattrib
flag. Test 2022-extension-scripts has been updated with a test case
that exercises this situation.
Sometimes it's useful to know whether an address referenced by a
function is a direct access, or is being used as a base address.
(I'm somewhat undecided on this one, since it clutters up the list
a bit. Giving it a try.)
The code was making an unwarranted assumption about how the flags
were being set. For example, ORA #$00 can't know if the previous
contents of the accumulator were nonzero, only that the instruction
hasn't made them nonzero, but instead of marking the Z-flag
"indeterminate" it was leaving the flag in its previous state. This
produces incorrect results if the previous instruction didn't set
its flags from the accumulator contents, e.g. it was an LDX.
Test 1003-flags-and-branches has been updated to test these states.
Some tests were duplicated between VisWireframe and the code that
consumed the data. We now expose the Validate function as a public
interface, and invoke it from WireframeObject. Failed validation
results in a null object being returned, which was previously allowed
but not actually checked for.
If you double-click a project symbol declaration, the symbol editor
opens. I found that I was double-clicking on the comment field and
typing with the expectation that the comment would be updated, but
it was actually setting the initial focus to the label field.
With this change the symbol editor will focus the label, value, or
comment field based on which column was double-clicked.
The behavior for Actions > Edit Project Symbol and other paths to the
symbol editor are unchanged.
Also, disabled a wayward assert.
SourceGen Edit Commands is a feature that allows you to generate
commands into a file and have SourceGen apply them to the current
project. I'm not expecting this to be used by anyone but me, so
for now I'm just adding an entry to the debug menu that can read
comments out of a file.
Also, fixed a bug in the re-centering min/max code that prevented
it from working on trivial shapes.
Also, renamed the atari-avg visualizer to atari-avg-bz, with the
expectation that one day somebody might want to create a variant
for newer games.
This converts AVG commands to wireframes. We don't try to track
color or intensity. (This is a disassembler, not a graphics
converter; perfection is not required.) The various rotation and
animation options are still enabled, though they're not terribly
useful for this.
Commands that are meant to be used in series, such as font glyphs,
tend to use (0,0) as their left edge and baseline. This puts the
shape in the upper-right corner of the thumbnail, which makes
everything smaller. The change adds a "re-center" option to the
wireframe renderer that computes the visible bounds and adjusts
the coordinates so that the center of the object is at (0,0) for
display.
This allows rendering of a vertex directly, rather than just as an
edge endpoint. They're currently drawn as small '+' signs. A
round dot would be better, but the code is passing a list of line
segments around, so this is simpler.
The code was wrong, but due to aggressive auto-label generation, it
rarely had an opportunity to express itself. The problem appeared
when you formatted a 16-bit value as an address, but the address
was outside the file and not associated with a project/platform
symbol. This fixes the glitch and adds some logging.
- Freeze Note brushes, so HTML export doesn't blow up when it tries
to access them.
- Add Ctrl+Shift+E as keyboard shortcut for File > Export.
- For code/data percentage, count inline data as data.
- Tweak code/data percentage text.
- Document Merlin32 '{' bug.
- Tweak tutorial text.
Don't show adjustments for operands that aren't full addresses. For
example, "LDA BLAH" shows an adjustment, but "LDA #>BLAH" does not.
This matches the behavior for internal addresses.
When generating the HTML anchor name element we need to remove the
trailing '?' from the label. It wasn't present in the hrefs, so all
links to annotated labels were broken.
The change to properly display adjustments to project/platform
symbol cross-references also added them to constants, but based on
the reference address rather than the operand value. We could
generate an adjustment from the value, but I'm not sure if that's
actually useful.
We were trying to use the in-file calculation for an external
address, so the adjustment was always zero.
Also, don't pass a fill brush for wireframe rendering. (No change
in behavior.)
Generation of HTML is extremely fast, but compressing thousands
of frames for wireframe animated GIFs can take a little while.
Sharing bitmaps between threads required two changes: (1) bitmaps
need to be "frozen" after being drawn; (2) you can't use Path because
BackgroundWorker isn't a STAThread. You can, however, use a
DrawingVisual / DrawingContext to do the rendering. Which is really
what I should have been doing all along; I just didn't know the
approach existed until I was forced to go looking for it.
Also, we now do a "run finalizers" call before generating an animated
GIF. Without it things explode after more than 10K GDI objects have
been allocated.
There's no "standard" coordinate system, so the choice is arbitrary.
However, an examination of the Transporter mesh in Elite revealed
that the mesh was designed for a left-handed coordinate system. We
can compensate for that trivially in the Elite visualizer, but we
might as well match what they're doing. (The only change required
in the code is a couple of sign changes on the Z coordinate, and an
update to the rotation matrix.)
This also downsizes Matrix44 to Matrix33, exposes the rotation mode
enum, and adds a left-handed ZYX rotation mode.
This does mean that meshes that put the front at +Z will show their
backsides initially, since we're now oriented as if we're flying
the ships rather than facing them. I considered adding a 180-degree
Y rotation (with a tweak to the rotation matrix handedness to correct
the first rotation axis) to have them facing by default, but figured
that might be confusing since +Z is supposed to be away.
Anybody who really wants it to be the other way can trivially flip
the coordinates in their visualizer (negate xc/zc).
The Z coordinates in the visualization test project were flipped so
that the design is still facing the viewer at rotation (0,0,0).