Implement multi-byte project/platform symbols by filling out a table
of addresses. Each symbol is "painted" into the table, replacing
an existing entry if the new entry has higher priority. This allows
us to handle overlapping entries, giving boosted priority to platform
symbols that are defined in .sym65 files loaded later.
The bounds on project/platform symbols are now rigidly defined. If
the "nearby" feature is enabled, references to SYM-1 will be picked
up, but we won't go hunting for SYM+1 unless the symbol is at least
two bytes wide.
The cost of adding a symbol to the symbol table is about the same,
but we don't have a quick way to remove a symbol.
Previously, if two platform symbols had the same value, the symbol
with the alphabetically lowest label would win. Now, the symbol
defined in the most-recently-loaded file wins. (If you define two
symbols with the same value in the same file, it's still resolved
alphabetically.) This allows the user to pick the winner by
arranging the load order of the platform symbol files.
Platform symbols now keep a reference to the file ident of the
symbol file that defined them, so we can show the symbols's source
in the Info panel.
These changes altered the behavior of test 2008-address-changes,
which includes some tests on external addresses that are close to
labeled internal addresses. The previous behavior essentially
treated user labels as being 3 bytes wide and extending outside the
file bounds, which was mildly convenient on occasion but felt a
little skanky. (We could do with a way to define external symbols
relative to internal symbols, for things like the source address of
code that gets relocated.)
Also, re-enabled some unit tests.
Also, added a bit of identifying stuff to CrashLog.txt.
Added a Width column to the list in the project symbol editor.
Changed the local variable table editor and the project symbol editor
to use DataGrid instead of ListView. This gets us easy sorting on
arbitrary columns. The previous code was reloading the display list
after every change; now we just add/edit/remove individual items,
which helps keep the list position and selection stable.
The ability to give explicit widths to local variables worked out
pretty well, so we're going to try adding the same thing to project
and platform symbols.
The first step is to allow widths to be specified in platform files,
and set with the project symbol editor. The DefSymbol editor is
also used for local variables, so a bit of dancing is required.
For platform/project symbols the width is optional, and is totally
ignored for constants. (For variables, constants are used for the
StackRel args, so the width is meaningful and required.)
We also now show the symbol's type (address or constant) and width
in the listing. This gets really distracting when overused, so we
only show it when the width is explicitly set. The default width
is 1, which most things will be, so users can make an aesthetic
choice there. (The place where widths make very little sense is when
the symbol represents a code entry point, rather than a data item.)
The maximum width of a local variable is now 256, but it's not
allowed to overlap with other variables or run of the end of the
direct page. The maximum width of a platform/project symbol is
65536, with bank-wrap behavior TBD.
The local variable table editor now refers to stack-relative
constants as such, rather than simply "constant", to make it clear
that it's not just defining an 8-bit constant.
Widths have been added to a handful of Apple II platform defs.
Change + save + undo + change was being treated as non-dirty.
Added link to "export" feature to documentation TOC.
Added keyboard shortcut for high part in data operand editor.
Corrected various things in the tutorial.
Added a blank line after local variable tables. Otherwise they
just sort of blend in with the stuff around them.
Put prefixes before the DOS 3.3 platform symbols.
Added a BAS_HBASH entry. We were getting BAS_HBASL and MON_GBASH
paired up, which looks weird.
Apply a very light tint to the preview section of the Edit Long
Comment dialog, to hint that the window is read-only.
HTML output should have had double quotes around internal anchors.
(Chrome and Edge didn't complain, but the w3c validator wasn't
happy.)
Made the text areas in the load-time problem report dialogs
scrollable.
Updated the manual.
The analyzer sometimes runs into things that don't seem right, like
hidden labels or references to non-existent symbols, but has no way
to report them. This adds a problem viewer.
I'm not quite ready to turn this into a real feature, so for now it's
a free-floating window accessed from the debug menu.
Also, updated some documentation.
Split "edit local variable table" into "create" and "edit prior".
The motivation is to allow the user to make changes to the most
recently defined table without having to go search for it. Having
table creation be an explicit action, rather than something that
just happens if you edit a table that isn't there, feels reasonable.
Show table offset in LV table edit dialog, so if you really want
to go find it there's a (clumsy) way to do so.
Increased the maximum width of a variable from 4 to 8. (This is
entirely arbitrary.)
Typing a long comment in the project symbol editor caused the
window to expand, which wasn't intended. Use the mono font in
the comment editor. Set the focus to the OK button after creating
or editing a project property. Show constant vs. address in the
info panel when an EQU directive is selected.
Changing an ASCII character operand back to default was going
through a path that tried to resolve low vs. high ASCII, which
isn't useful when you're removing the item. The root of the problem
was that the "default" button wasn't properly resetting the UI.
Also, updated keyboard shortcuts to be in sync with the instruction
operand editor.
It felt a little weird tying it to the asm generation setting,
so now it's just another checkbox in the export options.
Implemented the feature for plain text output. Did some rearranging
in the code. Fixed suppression of Notes in text and CSV.
We weren't escaping '<', '>', and '&', which caused browsers to get
very confused. Browsers seem to prefer <PRE> to <CODE> for long
blocks of text, so switch to that.
Also, added support for putting long labels on their own lines in
the HTML output.
Also, fixed some unescaped angle brackets in the manual.
Also, tweaked the edit instruction operand a bit more.
If you set things up just right, it's possible for flag status
changes to fail to get merged.
Added a regression test to 1003-flags-and-branches.
Also, tweaked the instruction operand editor to be a bit smoother
from the keyboard: added alt-key shortcuts, and put the focus on the
OK button after creating/editing a label so you can just hit the
return key twice.
I was using the plain names, but when you've got symbols like
READ and WAIT it's too easy to have a conflict and it's not plainly
obvious where something came from. Now all monitor symbols begin
with MON_, and Applesoft symbols begin with BAS_.
The Amper-fdraw example ended up with a few broken symbol refs,
because it was created before project/platform symbols followed the
"nearby" rules, and was explicitly naming LINNUM and AMPERV. I
switched the operands to default, and they now auto-format correctly.
I added a few more entries to Applesoft while I was at it.
I ran into a non-split table of 16-bit addresses, each of which
was (address-1) for a code location. I wanted to create a label,
add a code hint, and set the operand for each one, but there's no
easy way to do that.
It turns out the split-address table formatter can be made to work
for non-split tables with just a few minor changes.
It's possible to define multiple project symbols with the same
address. The way to resolve the ambiguity is to explicitly
reference the desired symbol from the operand. This was the
default behavior of the "create project symbol" shortcut in the
previous version.
It's rarely necessary, and it can get ugly if you rename a project
symbol, because we don't refactor operands in that case.
Also, removed "include symbol table" from export dialog. You can
exclude the table by removing it from the template, which right
now you'd need to do anyway to get rid of the H2 header and other
framing. To make this work correctly as an option we'd need to
parse the "div" in the template file and strip the whole section,
or split the template into multiple parts that get included as
needed. Not worth doing the work until we're sure it matters.
This feature "exports" the source code in the same format it appears
in on screen. The five columns on the left are optional, the four
on the right can be resized. Exported text can span the entire file
or just the current selection. Output can be plain text or CSV.
(I still haven't figured out a good use for CSV.)
The old copy-to-clipboard function is now implemented via the export
mechanism.
This adds a new clipboard mode that includes all columns. Potentially
useful for filing bug reports against SourceGen.
Ported the column width stuff from EditAppSettings, which it turns
out can be simplified slightly.
Moved the clipboard copy code out into its own class.
Disabled "File > Print", which has never done anything and isn't
likely to do anything in the near future.
Also, added a note to 2019-local-variables about a test case it
should probably have.
Updated the manual, and changed tutorial #2 to use local variables
for pointers.
If the symbol text box isn't empty, use the string as the initial
value for the Label when creating a new project property.
Fixed a crash when editing a project property.
Implemented local variable editing. Operands that have a local
variable reference, or are eligible to have one, can now be edited
directly from the instruction operand edit dialog.
Also, updated the code list double-click handler so that, if you
double-click on the opcode of an instruction that uses a local
variable reference, the selection and view will jump to the place
where that variable was defined.
Also, tweaked the way the References window refers to references
to an address that didn't use a symbol at that address. Updated
the explanation in the manual, which was a bit confusing.
Also, fixed some odds and ends in the manual.
Also, fixed a nasty infinite recursion bug (issue #47).
Rearrange the UI elements, and convert the code-behind to a more
XAML-style form. The basic stuff works, but the old "shortcut"
system is still in the process of being replaced.
This hits most of the edge cases, but doesn't exercise the two
duplicate name situations (var name same as user label, var name
same as project/platform symbol).
Also, fixed a bug in the EditDefSymbol uniqueness check where it
was comparing a symbol to itself.
Variables are now handled properly end-to-end, except for label
uniquification. So cc65 and ACME can't yet handle a file that
redefines a local variable.
This required a bunch of plumbing, but I think it came out okay.
We now generate FormatDescriptors with WeakSymbolRefs for direct
page references that match variable table entries.
LocalVariableTable got a rewrite. We need to be unique in both
name and address, but for the address we have to take the width into
account as well. We also want to sort the display by address
rather than name. (Some people might want it sorted by name, but
we can worry about that some other time.)
Updated the DefSymbol editor to require value uniqueness. Note
addresses and constants exist in separate namespaces.
The various symbols are added to the SymbolTable so that uniqueness
checks work correctly. This also allows the operand generation to
appear to work, but it doesn't yet handle redefinition of symbols.
Multi-line item, with one .eq line per variable definition. Add
one header line if "clear previous" is set.
Also, limit variable values to 0-255 in the editor. This is
somewhat arbitrary, but I think a focus on DP is useful.
This involved adding a list to the DisasmProject, creating a new
UndoableChange type, and writing the project file serialization
code. While doing the latter I realized that the new Width field
was redundant with the FormatDescriptor Length field, and removed it.
I added a placeholder line type, but we're not yet showing the
table in the display list. (To edit the tables you just have to
know where they are.)
The table editor is now editing the table, and the DefSymbol editor
now asks for the Width data when editing a local var.
This also moves EditDefSymbol closer to proper WPF style, with
bound properties for the input fields.
No changes yet to serialization or analysis.
Fixed a minor bug in GenerateLineList that would cause a blank line
to disappear under certain circumstances. Harmless, but odd.
Added a width property to DefSymbol.
Updated comments.
I didn't think it made sense, but I found something that used it,
so apparently it's a thing. This updates the operand editor to
let you choose PETSCII+DCI, and updates the assemblers to handle
it correctly (really just 64tass, since the others either don't
have a DCI directive or don't deal with PETSCII at all).
Changed the char-encoding sample from "bad dcI" to "pet dcI", and
updated the documentation.
String operands used to be simple -- each line had 62 characters
plus two hard-coded non-ASCII delimiters -- but now we're mixing
character and hex data, so we can't use simple math to tell where
the lines will break. We want to render them and keep the result
around until some dependency changes, e.g. different delimiters
or a change to the pseudo-op table.
Also, cleaned up LineListGen a little. It had some methods that
were declared static because they were expected to be shared, but
that never happened.
Also, fixed a bug in GatherEntityCounts where multi-line items were
being scanned multiple times.
The PseudoOpNames class is increasingly being used in situations
where mutability is undesirable. This change makes instances
immutable, eliminating the Copy() method and adding a constructor
that takes a Dictionary. The serialization code now operates on a
Dictionary instead of the class properties, but the JSON encoding is
identical, so this doesn't invalidate app settings file data.
Added an equality test to PseudoOpNames. In LineListGen, don't
reset the line list if the names haven't actually changed.
Use a table lookup for C64 character conversions. I figure that
should be faster than multiple conditionals on a modern x64 system.
Fixed a 64tass generator issue where we tried to query project
properties in a call that might not have a project available
(specifically, getting FormatConfig values out of the generator for
use in the "quick set" buttons for Display Format).
Fixed a regression test harness issue where, if the assembler reported
success but didn't actually generate output, an exception would be
thrown that halted the tests.
Increased the width of text entry fields on the Pseudo-Op tab of app
settings. The previous 8-character limit wasn't wide enough to hold
ACME's "!pseudopc". Also, use TrimEnd() to remove trailing spaces
(leading spaces are still allowed).
In the last couple of months, Win10 started stalling for a fraction
of a second when executing assemblers. It doesn't do this every
time; mostly it happens if it has been a while since the assembler
was run. My guess is this has to do with changes to the built-in
malware scanner. Whatever the case, we now change the mouse pointer
to a wait cursor while updating the assembler version cache.
Both dialogs got a couple extra radio buttons for selection of
single character operands. The data operand editor got a combo box
that lets you specify how it scans for viable strings.
Various string scanning methods were made more generic. This got a
little strange with auto-detection of low/high ASCII, but that was
mostly a matter of keeping the previous code around as a special
case.
Made C64 Screen Code DCI strings a thing that works.
A delimiter definition is four strings (prefix, open, close, suffix)
that are concatenated with the character or string data to form an
operand. A delimiter set is a collection of delimiter definitions,
with separate entries for each character encoding.
This is a convenient way to configure Formatter objects, import and
export data from the app settings file, and manage the UI needed to
allow the user to customize how things look.
The full set of options didn't fit on the first app settings tab, so
there's now a separate tab just for specifying character and string
delimiters. (This might be overkill, but there are various plausible
scenarios that make use of it.)
The delimiters for on-screen display of strings can now be
configured.
It's not quite the same as the character encoding -- sometimes we
want a mix of things -- so it gets its own enum. The value is
saved to the project file, but not actually used yet.
Also, moved some combo box strings into XAML resources.
Remove left/right arrow PNGs. Remove duplicate copies of icon.
Tweak some comments. Set application icon. Adjust padding on
group boxes in first tab of app settings.
The previous code output a character in single-quotes if it was
standard ASCII, double-quotes if high ASCII, or hex if it was neither
of those. If a flag was set, high ASCII would also be output as
hex.
The new system takes the character value and an encoding identifier.
The identifier selects the character converter and delimiter
pattern, and puts the two together to generate the operand.
While doing this I realized that I could trivially support high
ASCII character arguments in all assemblers by setting the delimiter
pattern to "'#' | $80".
In FormatDescriptor, I had previously renamed the "Ascii" sub-type
"LowAscii" so it wouldn't be confused, but I dislike filling the
project file with "LowAscii" when "Ascii" is more accurate and less
confusing. So I switched it back, and we now check the project
file version number when deciding what to do with an ASCII item.
The CharEncoding tests/converters were also renamed.
Moved the default delimiter patterns to the string table.
Widened the delimiter pattern input fields slightly. Added a read-
only TextBox with assorted non-typewriter quotes and things so
people have something to copy text from.
High ASCII and other encodings will be noted in the operand field,
not the opcode, so we no longer need these.
This removes the six input fields from the Pseudo-Op tab of app
settings. Values were stored as a serialized class in settings,
which generally works correctly as far as forward/backward
compatibility goes, so no worries there.
This also adds four "delimiter pattern" fields to the Code View tab,
allowing the user to customize how encoded strings are marked up
for the code list. The values aren't actually used yet.
Also, fixed an issue where changes to text fields on the Pseudo-Op
tab weren't raising the dirty flag.
We've been treating ASCII strings and instruction/data operands as
ambiguous, resolving low vs. high when generating output for the
display or assembler. This change splits it into two separate
formats, simplifying output generation.
The UI will continue to treat low/high ASCII as as single thing,
selecting the format appropriately based on the data. There's no
reason to have two radio buttons that are never both enabled.
The data operand string functions need some additional work, but
that overlaps substantially with the upcoming PETSCII changes, so
for now all strings set by the data operand editor are low ASCII.
The file format has changed again, but since there hasn't been a
release since the previous change, I'm leaving the file format
at v2. Code has been added to resolve the ASCII mode when loading
a v1 project file.
This removes some complexity from the assembly code generators.
We used to use type="String", with the sub-type indicating whether
the string was null-terminated, prefixed with a length, or whatever.
This didn't leave much room for specifying a character encoding,
which is orthogonal to the sub-type.
What we actually want is to have the type specify the string type,
and then have the sub-type determine the character encoding. These
sub-types can also be used with the Numeric type to specify the
encoding of character operands.
This change updates the enum definitions and the various bits of
code that use them, but does not add any code for working with
non-ASCII character encodings.
The project file version number was incremented to 2, since the new
FormatDescriptor serialization is mildly incompatible with the old.
(Won't explode, but it'll post a complaint and ignore the stuff
it doesn't recognize.)
While I was at it, I finished removing DciReverse. It's still part
of the 2005-string-types regression test, which currently fails
because the generated source doesn't match.
WDM <arg> now works. MVN/MVP are still broken. Correct code is
generated for whichever version of the assembler is configured.
Regression tests updated for new version.
Also, fixed a UI bug where manual edits to the assembler path were
being ignored.
- Updated the tutorial to track changes to WPF, and to clarify
existing content.
- Fixed Ctrl+H Ctrl+C, which was getting masked by the Copy command
handler.
- Fixed initial selection of address in Set Address.
- MakeDist now copies CommonWPF.dll.
- Spent a bunch of time tracking down a null-pointer deref that only
happened when you didn't start with a config file. Fixed.
- The NPE was causing the program to exit without any sort of useful
diagnostic, so I added an uncaught exception handler that writes
the crash to a text file in the current directory.
- Added a trace listener definition to App.config that writes log
messages to a file, but it can't generally be enabled at runtime
because you can't write files from inside the sandbox. So it's
there but commented out.
- Made the initial size of the main window a little wider.