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).
Elite has a level-of-detail cutoff in the mesh data. This change
provides a way for the visualization generator to exclude vertices
and edges that should not be rendered based on the desired LOD.
Experimented with different orders of rotation for wireframe viewer.
Made perspective projection the default behavior. Removed animation
parameters from the stored Visualization when it's not animated.
The visualization editor uses the parameters from the most recent
edit as the defaults when creating a new visualization. This change
extends the behavior to the view controls for wireframes.
Also, tweak the perspective projection scaling to fill out the area
a bit more, and change the visualization editor to use the grid's
size when setting the path dimensions.
Also, note gimbal lock.
Remember how object references from plugins are proxy objects that
time out if you don't access them for a while? I didn't either.
This reshuffles the code to keep WireframeObject references rather
than IVisualizationWireframe.
Handle the remaining visualization editor UI controls, except for
the "test" button. Save/restore wireframe animations in the
project file. Changed the preview from a 1-pixel-wide line drawn
by a path half the window size to a 2-pixel-wide line drawn by a
path the exact window size.
Moved X/Y/Z rotation out of the plugin, since it has nothing to do
with the plugin at all. (Backface removal and perspective projection
are somewhat based on the data contents, as is the choice for
whether or not they should be options.)
Added sliders for X/Y/Z rotation. Much more fun that way.
Renamed VisualizationAnimation to VisBitmapAnimation, as we're not
going to use it for wireframe animation. Created a new class to
hold wireframe animation data, which is really just a reference to
the IVisualizationWireframe so we can generate an animated GIF
without having to pry open the plugin again.
Renamed the "frame-delay-msec" parameter, which should start with
an underscore to ensure it doesn't clash with plugin parameters.
If we don't find it with an underscore we check again without for
backward compatibility.
We extract the data from the wireframe visualization, perform a
trivial transform, and display it. The perspective vs.
orthographic flag in the parameters is respected. (No rotation or
backface removal yet.)
Also, increased the thumbnail sizes in the visualization set editor
list from 48x48 to 64x64, because the nearest-pixel-scaled 48x48
looks nasty when used for wireframes.
I did a bunch of experiments to characterize line drawing. Long
story short: end points are inclusive, and coordinates should be
offset by +0.5 to avoid anti-aliasing effects.
Added some more plumbing. Updated visualization set edit dialog,
which now does word-wrapping correctly in the buttons. Added Alt+V
as the hotkey for Create/Edit Visualization Set, which allows you
to double-tap it to leap into the visualization editor.
Experimented with Path drawing, which looks like it could do just
what we need.
Also, show the file size in KB in the code/data/junk breakdown at the
bottom of the window. (Technically it's KiB, but that looked funny.)
These were being overlooked because they didn't actually cause
anything to happen (a no-op .ORG sets the address to what it would
already have been). The assembly source generator works in a way
that causes them to be skipped, so everybody was happy.
This seemed like the sort of thing that was likely to cause problems
down the road, however, so we now split regions correctly when a
no-op .ORG is encountered. This affects the uncategorized data
analyzer and selection grouping.
This changed the behavior of the 2004-numeric-types test, which was
visibly weird in the UI but generated correct output.
Added the 2024-ui-edge-cases test to provide a place to exercise
edge cases when testing the UI by hand. It has some value for the
automated regression test, so it's included there.
Also, changed the AddressMapEntry objects to be immutable. This
is handy when passing lists of them around.
Added a new category "sprite sheet", which is essentially a more
generalized version of the bitmap font renderer. It has the full
set of options for col/row/cell stride and colors. (Issue #74,
issue #75)
Added a flag that flips the high bits on bitmaps. Sometimes data
is stored with the high bit clear, but the high bit is set as it's
rendered. (Issue #76)
Also, fixed the keyboard shortcuts in the Edit Visualization Set
window, which were 'N' for both "New ___" items. (Issue #57)
Added accelerator keys to Mixed and Null strings. (Issue #67)
Added units to string counts. (Issue #68) Added proper handling
for plural/singular for bytes and strings. Changed N/A indicator
from "xx" to "--".
Added "show undocumented opcodes" checkbox, so you can choose
whether or not to see them at all. (Issue #60)
Added formatter call for the instruction mnemonics so they get
capitalized when the app is configured for upper-case opcodes.
(Issue #59)
Fix a bug where the instruction chart and ASCII chart were writing
their modes to the same setting, stomping each other.
Also, pluralized a button in the file concatenator.
For nonzero values we were leaving Z=prev, which is wrong when Z=0
because the AND result might be zero. Now if Z=1 we leave it alone,
but if Z=0 we now set it to Z=?.
Test 1003-flags-and-branches was testing for the (incorrect)
behavior, so we're now running into a BRK. This is fine.
When editing an instruction operand, if you click "edit project
symbol", we need an initial value for the label. If you started
typing something in the instruction operand symbol field, we use
that. Unfortunately we were trying to use that even when it was
invalid, which caused an assertion to go off in the DefSymbol
constructor.
Double-clicking the opcode of an instruction that references a
local variable (e.g. "LDA ]foo") moves the selection to the line
that declares the variable. This wasn't working in the case where
the local var was annotated (e.g. "LDA ]foo?").
We want to be able to declare a symbol for a struct or buffer that
spans the entire width, and then declare more-specific items within
it that take precedence. This worked for everything but the very
first byte, because on an exact match we were resolving the conflict
alphabetically.
Now, if one is wider than the other, we use the narrower definition.
Updated 2021-external-symbols with some additional test cases.
The VisParamDescrs specify a type and a default value. If the value
has the wrong type, things would blow up in the editor. We now
check the type at plugin load time, and refuse to load the plugin at
all if an entry has a bad type.
The DisplayList update function was mis-handling the case where
there were no previous lines. This caused assertions to fire for
the case where you add a header comment to a project with no
existing header comment or EQUs.
We're doing this for user labels but not for project/platform
symbols. So if you have a constant named "BCC" you can't assemble
your code with certain assemblers. Now we rename it automatically.
Added a quick test to 2007-labels-and-symbols. (No change to ACME,
which barfs on the test.)
The "is the .junk alignment directive correct" was returning true
for subtype=None (not aligned), which caused execution to go down
the wrong path and irritate an assert.
We're generating names that nothing links to. The names aren't
guaranteed unique, so they're of dubious value anyway.
Also, fixed the Atari 2600 visualizer script filename in sys defs.
In 1.5.0-dev1, as part of changes to the way label localization
works, the local variable de-duplicator started checking against a
filtered copy of the symbol table. Unfortunately it never
re-generated the table, so a long-lived LocalVariableLookup (like
the one used by LineListGen) would set up the dup map wrong and
be inconsistent with other parts of the program.
We now regenerate the table on every Reset().
The de-duplication stuff also had problems when opcodes and
operands were double-clicked on. When the opcode is clicked, the
selection should jump to the appropriate variable declaration, but
it wasn't being found because the label generated in the list was
in its original form. Fixed.
When an instruction operand is double-clicked, the instruction operand
editor opens with an "edit variable" shortcut. This was showing
the de-duplicated name, which isn't necessarily a bad thing, but it
was passing that value on to the DefSymbol editor, which thought it
was being asked to create a new entry. Fixed. (Entering the editor
through the LvTable editor works correctly, with nary a de-duplicated
name in sight. You'll be forced to rename it because it'll fail the
uniqueness test.)
References to de-duplicated local variables were getting lost when
the symbol's label was replaced (due largely to a convenient but
flawed shortcut: xrefs are attached to DefSymbol objects). Fixed by
linking the XrefSets.
Given the many issues and their relative subtlety, I decided to make
the modified names more obvious, and went back to the "_DUPn" naming
strategy. (I'm also considering just making it an error and
discarding conflicting entries during analysis... this is much more
complicated than I expected it to be.)
Quick tests can be performed in 2019-local-variables:
- go to +000026, double-click on the opcode, confirm sel change
- go to +000026, double-click on the operand, confirm orig name
shown in shortcut and that shortcut opens editor with orig name
- go to +00001a, down a line, click on PROJ_ZERO_DUP1 and confirm
that it has a single reference (from +000026)
- double-click on var table and confirm editing entry
The list of EQUs at the top of the file is sorted, by type, then
value, then name. This adds width as an additional check, so that
if you have overlapping items the widest comes first.
This is nice when you have a general entry for a block of data, and
then specific entries for some locations within the block.
We emit address adjustments like "LDA thing+1", which are usually
small values. Sometimes they're large, e.g. "LDA thing-61440",
which is harder to understand than "LDA thing-$F000". So now we
show small adjustments in decimal, and large adjustments in hex.
The current definition of "small" is abs(adjust) < 256.
When a project is opened, the main window layout subtly changes.
Of particular note: the vertical splitters below the references and
symbols windows shift upward 1 pixel when a project is opened, and
back down a pixel when the project is closed. So if you close the
app while a project is open, the settings file gets updated with the
new values for the sliders. If you restart the app a lot the effect
becomes noticeably fairly quickly.
I'm not yet sure what's causing this. I'm currently working around
the issue by not updating the window sizes in the settings file if
they're off by only one pixel.
- Break up long sequences of visualization images in exported HTML
to avoid horizontal scrolling. Lines don't fold in "pre" mode,
and switching out of "pre" is ugly, so we just break at an
arbitrary point.
- Use a slightly different filename for animated GIFs.
- When moving items up/down in the visualization set editor or
bitmap animation editor, scroll the datagrid to keep the selected
item in view.
- Fix a wayward assert.
Remember the most recent set of parameters, and use them as defaults
when creating a new visualization. This is very helpful when
creating visualizations for multiple frames of an animation.
After exiting an editor, focus on the "OK" button in the visualization
set editor. This allows a quick double-Enter after an edit.
No meaningful change to the format itself, just to the way it's
formatted. Specifically, we now emit a line break after every
comma rather than only at curly braces.
The problem driving this change is that all end-of-line comments
are stored in a single dictionary, which becomes a single long line.
Most source control tools can't diff or merge that in a useful way.
Having every element on its own line makes some things harder to
read, but in the end I'm more interested in machine readability
than human readability.
(I tested this by saving all SGTestData projects and verifying that
they worked. I didn't check the updated versions in because it's
kind of nice to have older project files around to confirm that I'm
not breaking backward compatibility.)
The uncategorized data scanner isn't supposed to create strings or
".fill" directives that straddle labels, long comments, notes,
visualizations, or ORG directives. The test for crossing an ORG
directive is incomplete, and doesn't correctly handle no-op ORGs
(where the new address is the same as the old address).
The code generator doesn't output ORGs that are hidden inside other
things, so we're not generating bad code, but it looks funny on
screen and may cause problems later on. The 2004-numeric-types test
has the basic .align/.fill/.bulk directive tests, and now has an
extended set of tests for uncategorized data region splitting.
Should be solid/transparent not white/black. Added a blue color
to the palette to use for sprites, as white + transparent disappears
completely on web pages with a white background.
Black + white + grey seems fine for playfields.
The tool allows you to cut a piece out of a file by specifying an
offset and a length. A pair of hex dumps helps you verify that the
positions are correct.
Also, minor cleanups elsewhere.
The visualization editor was retaining an IPlugin reference for the
visualization generator selection combo box. After 5 minutes the
proxy object timed out, so if you left the editor open and inactive
for that long you'd start getting weird errors.
We now keep the script identifier string and use that to get a
fresh IPlugin proxy object.
Defined a simple monochrome bitmap format, and created some pieces
for a Tic-Tac-Toe game. Wrote a tutorial that explains how to
visualize them.
Also, updated some comments.
If you have a single line selected, Set Address adds a .ORG directive
that changes the addresses of all following data, until the next .ORG
directive is reached. Sometimes code will relocate part of itself,
and it's useful to be able to set the address at the end of the block
to what it would have been before the .ORG change.
If you have multiple lines selected, we now add the second .ORG to
the offset that follows the last selected line.
Also, fixed a bug in the Symbol value updater that wasn't handling
non-unique labels correctly.
As with still images, animations are rendered at original size and
then scaled with HTML properties.
Also, fixed the blurry scaling on animation thumbnails. I couldn't
find a way to do nearest-neighbor scaling in the code-behind without
resorting to System.Drawing (WinForms), so I added an overlay image
to the various grids.
Visualization animations are now exported as animated GIFs. The
Windows stuff is a bit lame so I threw together some code that
stitches a bunch of GIFs together.
The GIF doesn't quite match the preview, because the preview scales
the individual frames, while the animated GIF uses the largest frame
as the size and is then scaled based on that. Animating frames of
differing sizes together is bound to be trouble anyway, so I'm not
sure how much to fret over this.
We now store Visualizations, VisualizationAnimations, and
VisualizationSets as three separate lists linked by tag strings.
WARNING: this breaks existing projects with visualizations. The
test projects have been updated.
The UI was moving items from the source list to the animation list,
but there's no reason why the same thing can't appear more than once.
You can no longer hit "Add" repeatedly to add multiple consecutive
items, but you can now multi-select in the source list to add several
things at once.
Bitmap animations are composed of a sequence of other visualizations.
This is all well and good until a visualization is deleted, at which
point all animations in all sets in the entire project have to be
checked and potentially changed, and perhaps even removed (if all of
the animation's members have been removed). This turns out to be
kind of annoying to deal with, but it's better to deal with it in
code than force the user to manually update broken animations.
This change adds thumbnails for the animations, currently generated
by offscreen composition. This approach doesn't work quite right.
This adds a new class and a rough GUI for the editor. Animated
visualizations take a collection of bitmaps and display them in
sequence. (This will eventually become an animated GIF.)
Fixed the issue where changes to tags in the set currently being
edited weren't visible to the tag uniqueness check when editing other
items in the same set.
We now generate GIF images for visualizations and add inline
references to them in the HTML output.
Images are scaled using the HTML img properties. This works well
on some browsers, but others insist on "smooth" scaling that blurs
out the pixels. This may require a workaround.
An extra blank line is now added above visualizations. This helps
keep the image and data visually grouped.
The Apple II bitmap test project was updated to have a visualization
set with multiple images at the top of the file.
(1) Added an option to limit the number of bytes per line. This is
handy for things like bitmaps, where you might want to put (say) 3
or 8 bytes per line to reflect the structure.
(2) Added an application setting that determines whether the screen
listing shows Merlin/ACME dense hex (20edfd) or 64tass/cc65 hex bytes
($20,$ed,$fd). Made the setting part of the assembler-driven display
definitions. Updated 64tass+cc65 to use ".byte" as their dense hex
pseudo-op, and to use the updated formatter code. No changes to
regression test output.
(Changes were requested in issue #42.)
Also, added a resize gripper to the bottom-right corner of the main
window. (These seem to have generally fallen out of favor, but I
like having it there.)
- Show the full path in the tooltip for the two "recent project"
buttons shown on the launch panel.
- Reset the app title bar and status bar contents when the project
is closed.
Added comments, renamed files, removed cruft.
Stop showing the visualization tag name in the code list. It's
often redundant with the code label, and it's distracting. (We may
want to make this an option so you can Ctrl+F to find a tag.)
First swing at a visualizer for Atari 2600 sprites and playfields.
Won't necessarily present an accurate view of what is displayed on
screen, but should provide a reasonable shape for data stored in
the obvious way.
The Adventure playfields looked squashed, so I added a simple row
duplication value.
Also, minor improvements to visualizers generally:
- Throw an exception, rather than an Assert, in VisBitmap8 when the
arguments are bad.
- Show the exception in the Visualization Edit dialog.
- If generation fails and we don't have an error message, show a
generic "stuff be broke" string.
- Set focus on OK button in Visualization Set Edit after editing,
so you can hit Enter twice after renaming a tag.
Various changes:
- Generally treat visualization sets like long comments and notes
when it comes to defining data region boundaries. (We were doing
this for selections; now we're also doing it for format-as-word
and in the data analyzer when scanning for strings/fill.)
- Clear the visualization cache when the address map is altered.
This is necessary for visualizers that dereference addresses.
- Read the Apple II screen image from a series of addresses rather
than a series of offsets. This allows it to work when the image
is contiguous in memory but split into chunks in the file.
- Put 1 pixel of padding around the images in the main code list,
so they don't blend into the background.
- Remember the last visualizer used, so we can re-use it the next
time the user selects "new".
- Move min-size hack from Loaded to ContentRendered, as it apparently
spoils CenterOwner placement.
Report visualization generation errors through an explicit
IApplication interface, instead of pulling messages out of the
DebugLog stream.
Declare that GetVisGenDescrs() is only called when the plugin is in
the "prepared" state, so that plugins can taylor the set based on
the contents of the file. (This could be used to set min/max on
the "offset" entries, but I want special handling for offsets, so
we might as well set it later.)
Bitmap fonts are a series of (usually) 1x8 bitmaps, which we arrange
into a grid of cells.
Screen images are useful for embedded screens, or for people who want
to display stand-alone image files as disassembly projects.
Various improvements:
- Switched to ReadOnlyDictionary in Visualization to make it clear
that the parameter dictionary should not be modified.
- Added a warning to the Visualization Set editor that appears when
there are no plugins that implement a visualizer.
- Make sure an item is selected in the set editor after edit/remove.
- Replaced the checkerboard background with one that's a little bit
more grey, so it's more distinct from white pixel data.
- Added a new Apple II hi-res color converter whose output more
closely matches KEGS and AppleWin RGB.
- Added VisHiRes.cs to some Apple II system definitions.
- Added some test bitmaps for Apple II hi-res to the test directory.
(These are not part of an automated test.)
Thumbnails are now visible in the main list and in the visualization
set editor. They're generated on first need, and regenerated when
the set of plugins changes.
Added a checkerboard background for the visualization editor bitmap
preview. (It looks all official now.)
The Visualization and Visualization Set editors are now fully
functional. You can create, edit, and rearrange sets, and they're
now stored in the project file.
Implemented Apple II hi-res bitmap conversion. Supports B&W and
color. Uses essentially the same algorithm as CiderPress.
Experimented with displaying non-text items in ListView. I assumed
it would work, since it's the sort of thing WPF is designed to do,
but it's always wise to approach with caution. Visualization Sets
now show a 64x64 button as a placeholder for the eventual thumbnail.
Some things were being flaky, which turned out to be because I
wasn't Prepare()ing the plugins before using them from Edit
Visualization. To make this a deterministic failure I added an
Unprepare() call that tells the plugin that we're all done.
NOTE: this breaks all existing plugins.
Added some rudimentary bitmap creation code. Got a test pattern
generated by the plugin to display in the app. (Most of the time
required for this was spent figuring out how bitmaps are handled
in WPF.)
Got parameter in/out working in EditVisualization dialog. Did some
rearranging in PluginCommon interfaces and data structures. Still
doesn't do anything useful.
Basic infrastructure for taking a list of parameters from a plugin
and turning it into a collection of UI controls, merging in values
from a Visualization object. Doesn't yet do anything useful.
WPF makes the hard things easy and the easy things hard. This was
a hard thing, so it was easy to do (with some helpful sample code).
Yay WPF?
It's pretty common for code to access BUFFER-1,X, but it's rare for
the buffer to live on zero page memory. More often than not we're
auto-formatting zero-page operands with a nearby symbol when they're
just simple variables. It's more confusing than useful, so we don't
do that anymore.
Updated documentation for non-unique label changes. Added a new
section to tutorial #1.
Updated examples to use non-unique labels and variable tables.
Tweaked the EditLabel radio button names.
Correct handling of local variables. We now correctly uniquify them
with regard to non-unique labels. Because local vars can effectively
have global scope we mostly want to treat them as global, but they're
uniquified relative to other globals very late in the process, so we
can't just throw them in the symbol table and be done. Fortunately
local variables exist in a separate namespace, so we just need to
uniquify the variables relative to the post-localization symbol table.
In other words, we take the symbol table, apply the label map, and
rename any variable that clashes.
This also fixes an older problem where we weren't masking the
leading '_' on variable labels when generating 64tass output.
The code list now makes non-unique labels obvious, but you can't tell
the difference between unique global and unique local. What's more,
the default type value in Edit Label is now adjusted to Global for
unique locals that were auto-generated. To make it a bit easier to
figure out what's what, the Info panel now has a "label type" line
that reports the type.
The 2023-non-unique-labels test had some additional tests added to
exercise conflicts with local variables. The 2019-local-variables
test output changed slightly because the de-duplicated variable
naming convention was simplified.
Implemented assembly source generation of non-unique local labels.
The new 2023-non-unique-labels test exercises various edge cases
(though we're still missing local variable interaction).
The format of uniquified labels changed slightly, so the expected
output of 2012-label-localizer needed to be updated.
This changes the "no opcode mnemonics" and "mask leading underscores"
functions into integrated parts of the label localization process.
The label localizer is now always on. The regression tests turned
it off by default, but that's no longer allowed, so the generated
output has changed for many of them. The tests themselves were not
altered.
Update the symbol lookup in EditInstructionOperand, EditDataOperand,
and GotoBox to correctly deal with non-unique labels.
This is a little awkward because we're doing lookups by name on
a non-unique symbol, and must resolve the ambiguity. In the case of
an instruction operand that refers to an address this is pretty
straightforward. For partial bytes (LDA #>:foo) or data directives
(.DD1 :foo) we have to take a guess. We can probably make a more
informed guess than we currently are, e.g. the LDA case could find
the label that minimizes the adjustment, but I don't want to sink a
lot of time into this until I'm sure it'll be useful.
Data operands with multiple regions are something of a challenge,
but I'm not sure specifying a single symbol for multiple locations
is important.
The "goto" box just finds the match that's closest to the selection.
Unlike "find", it always grabs the closest, not the next one forward.
(Not sure if this is useful or confusing.)
Added serialization of non-unique labels to project files.
The address labels are stored without the non-unique tag, because we
can get that from the file offset. (If we stored it, we'd need to
extract the value and verify that it matches the offset.) Operand
weak references are symbolic, and so do include the tag string.
We weren't validating symbol labels before. Now we are.
This also adds a "NonU" filter to the Symbols window so the labels
can be shown or hidden as desired.
Also, added source for a first pass at a regression test.
- Renamed "strip label prefix/suffix" to "omit label prefix/suffix".
- Changed a Merlin operand workaround so it doesn't apply to code
that is explicitly not in bank zero.
- Changed {addr}/{const} annotations on project/platform symbol
equates so they line up a little better on screen and in exported
sources.
Continue development of non-unique labels. The actual labels are
still unique, because we append a uniquifier tag, which gets added
and removed behind the scenes. We're currently using the six-digit
hex file offset because this is only used for internal address
symbols.
The label editor and most of the formatters have been updated. We
can't yet assemble code that includes non-unique labels, but older
stuff hasn't been broken.
This removes the "disable label localization" property, since that's
fundamentally incompatible with what we're doing, and adds a non-
unique label prefix setting so you can put '@' or ':' in front of
your should-be-local labels.
Also, fixed a field name typo.
This adds the concept of label annotations. The primary driver of
the feature is the desire to note that sometimes you know what a
thing is, but sometimes you're just taking an educated guess.
Instead of writing "high_score_maybe", you can now write "high_score?",
which is more compact and consistent. The annotations are stripped
off when generating source code, making them similar to Notes.
I also created a "Generated" annotation for the labels that are
synthesized by the address table formatter, but don't modify the
label for them, because there's not much need to remind the user
that "T1234" was generated by algorithm.
This also lays some of the groundwork for non-unique labels.
If an address map entry wraps around the end of a bank, add a note
to the message log. This is Error level, since some assemblers
will refuse to handle it.
It's too easy to hit Escape after making a bunch of changes, so
now we ask for confirmation.
(Might make sense to make this strictly an Esc guard, and not
pester the user if they actually hit the Cancel button or close
box. I'm not convinced though; Esc+Enter isn't terrible.)
Some style guides say you should only put one space between
sentences, but I and many others still put two. The line-folding
code was only eating one of them when they straddled the end of the
line, which looked a little funny because the following line was
indented by one space.
This tweaks the code to eat both spaces. Regression test updated.
Also, nudge some UI elements so they line up.
Jumps to the first offset associated with the change at the top of
the Undo stack. We generally jump to the code/data offset, not the
specific line affected. It's possible to do better (and we do, for
Notes), but probably not worthwhile.
As noted in issue #52, the side panels can't be resized once the
ListView gets focus. The root of the problem is a workaround for a
selection problem that involves catching the Item Container
Generator's Status Changed event, and setting an item's focus. It
appears that changing the size of the ListView causes the
StatusChanged event to fire, which cause the handler to grab the
focus, which causes the splitters to stop moving after one step.
This change adds a workaround that prevents the original workaround
from doing anything while a splitter is in the process of being
dragged. It doesn't solve all problems -- you can't move the
splitters more than one step with the keyboard -- but it allows them
to be dragged around with the mouse.
There's got to be a better way to deal with this.
Copied the extension script tutorial files out of the Scripts
directory and into the Tutorial directory. This makes more sense,
and makes it possible to expand the script sample without altering
the tutorial.
Reverted the Scripts sample to be an actual sample, rather than a
tutorial.
Renumbered the last two tutorials and added them to the ToC. This
gives them actual numbers rather than treating them as add-ons to
the advanced tutorial.
Moved the source files for the tutorial binaries into a subdirectory
to reduce clutter.
This does mean we have two separate copies of the inline string
sample plugins, but that's an artifact of our attempts at security.
The code that found a nearby data target for an instruction operand
was searching backward but not forward. We now take one step
forward, so that "LDA TABLE-1,Y" fills in automatically.
This altered 2008-address-changes, which had just this situation.
It didn't alter 2010-target-adjustment, but the existing tests were
insufficient and have been improved.
The fix for Shift+F3 required briefly switching the code list view
to single-select mode. Unfortunately, while in that mode the
control throws an exception if you touch SelectedItems (plural)
rather than SelectedItem (singular), and in an unusual case the
selection-changed event handler was doing just that.
If a local variable table gets buried, it won't appear in the code
list, so most things ignore it. Unfortunately, the code that adds
new entries and edits tables was finding them, which was causing
variable definitions to appear to fall into a black hole.
This is addressed in two ways. First, we now add a message to the
log when a hidden table is noticed. Second, the code that finds
the nearest prior table now keeps track of hidden vs. not hidden.
If a non-hidden table is available, that is returned. If the only
option is a hidden table, we will return that, because the callers
have already assumed that a table exists by virtue of its presence
in the LvTable list.
Project symbol address values are now limited to positive 24-bit
integers, just as they are for platform symbols. Constants may
still be 32-bit values.
While disassembling some code I found that I wanted the ROM entry
points, but the zero page usage was significantly different and the
ROM labels were distracting. Splitting the symbol file in two was
a possibility, but I'm afraid this will lead to a very large
collection of very small files, and we'll lose any sense of relation
between the ROM entry points and the ZP addresses used to pass
arguments.
Platform symbols have the lowest priority when resolving by address,
but using that to hide the unwanted labels requires creating project
symbols or local variables for things that you might not know what
they do yet. It's possible to hide a platform symbol by adding
another symbol with the same label and an invalid value.
This change formalizes and extends the "hiding" of platform symbols
to full erasure, so that they don't clutter up the symbol table.
This also tightens up the platform symbol parser to only accept
values in the range 0 <= value <= 0x00ffffff (24-bit positive
integers).
An "F8-ROM-nozp" symbol file is now part of the standard set. A
project can include that to erase the zero-page definitions.
(I'm not entirely convinced this is the right approach, so I'm not
doing this treatment on other symbol files... consider this an
experiment. Another approach would be some sort of conditional
inclusion, or perhaps erase-by-tag, but that requires some UI work
in the app to define what you want included or excluded.)
- Allow user to "unnecessarily" set an address override. This is
a handy thing to do when dealing with code that does a lot of
relocations.
- Moved "save needed" text to the end of the title string.
- Updated F8-ROM syms.
- Added ProDOS 8 error code constants