Some 16-bit operands are tracked internally as 24-bit, appending the
B (data bank) or K (program bank) register to form the full address.
For some assemblers the K-bank instructions must be output as 24-bit
values, even for 16-bit JMP/JSR, but for most we want to strip the
bank byte off before outputting the operand as hex or decimal.
This expands 20032-labels-and-symbols with a mix of 24-bit, 16-bit+B,
and 16-bit+K instructions formatted in various ways. No existing
tests were affected by this change.
(issue #172)
We were treating PEA's operand as an absolute address and attempting to
extend it to 24 bits. This wasn't very successful, and was
counter-productive when the argument was actually a constant, which is
common. Worse, if the operand appeared to reference an internal address
outside bank 0, we would output a 24-bit value, breaking 64tass and cc65.
We now treat PEA as having an immediate operand. (It was already
classified as an "extended immediate", but the operand-address
computation was still happening.)
This will have little to no effect on projects that use OMF relocation
data, because PEA arguments are explicitly identified as symbols or
constants.
New tests were added to 20032-labels-and-symbols to exercise the code
generation failures. A few other tests that used PEA were affected.
20152-local-variables was fixed by adding a symbolic reference, the
others remained as-is and the expected output was revised.
(issue #172)
This allows signed decimal operands to be formatted as such, e.g.
"LDA #$FE" becomes "LDA #-2". This can be applied to immediate
operands and to numeric data pseudo-ops.
Not all assemblers support this in all situations. The asm generators
will output unsigned decimal operands if so.
The 20020- and 20022-operand-formats tests have been updated.
When asked to tag an absolute JMP instruction ($4C) as code, we now
scan forward to see if it's the start of a series of JMPs. If we
find more than one, we offer the opportunity to tag the entire set
all at once.
A series of unformatted JMPs has been added to 20200-ui-edge-cases
for manual testing.
(issue #22)
The existing workaround for broken Merlin 32 behavior is sufficient
to handle the new test cases. This updates 20032-labels-and-symbols
to fully exercise all DP addressing modes with non-DP labels.
(issue #170)
Most assemblers treat '<' and '>' as byte-select operators. Merlin 32
treats them as shift operators, making '<' effectively a no-op. A
mask is applied based on the length implied by the opcode or pseudo-op,
e.g. "DFB <FOO" will mask off the high bits. This is problematic for
instructions like "LDA <FOO", where the choice between absolute and DP
addressing depends on the value of "<FOO". If FOO is >= $100, the
lack of masking will cause it be treated as absolute. There is
currently no other mechanism to force the use of a direct-page opcode.
The only recourse is to append "&$ff" to the operand, so the
assembler knows that it can be handled as a DP op. The code generator
has been updated to add "&$ff" where needed, based on the label's
value. Unfortunately the assembler doesn't accept this for certain
specific addressing modes; this appears to be a bug.
The relevant test cases (2003x-labels-and-symbols) have been updated
to exercise these situations. The current test projects side-step the
failing assembler behavior by using a DP label instead. These should
be changed to correctly exercise the full behavior, with the code
generator outputting the instructions as raw hex values to work
around bugs.
There are some deliberately broken things (like a duplicate label) in
the 20030 case that were copied into the 20032 case when it was
created. For ease of editing these have been removed from 20032.
(issue #170)
This adds a shortcut for editing the label at the address referenced
by an instruction operand or data address pseudo-op. This can be
activated from the Actions menu, or with Ctrl+Shift+L.
For references inside the file, the Edit Label dialog is opened. For
external addresses, the project symbol editor is opened.
Local variable table entries are currently not supported.
(issue #166)
The code that allowed easy editing of project symbol operands wasn't
handling overlapping multi-byte regions correctly.
This adds a new section to the 20200-ui-edge-cases test case that has
instructions with various kinds of address operands.
Added a "format help" button to the long comment edit window. This
brings up a quick summary of the format tags in a modal dialog.
Updated documentation and tutorial.
Started implementing the fancy formatter. It currently doesn't do
anything fancy, just word-wrapping.
Moved the static DebugShowRuler field into Formatter, so that the
cached data is discarded when the setting changes.
Also, updated SourceNotes with instructions for publishing a release.
Added a "fancy" flag to MultiLineComment. If set, we will use
formatting commands embedded in the text itself. The max width pop-up
and "boxed" flag will be ignored in favor of width and boxing
directives. (See issue #111.)
The current "fancy" formatter is just a placeholder that folds lines
every 10 characters.
Removed FormattedMlcCache (added two changes back). Caching the
rendered string list in the MLC itself is simpler and more efficient
than having a separate cache, and it works for Notes as well.
Added anchors for more comments in the 20090 test.
While it's okay to use ';', the classic Merlin editor will treat it
as an end-of-line comment and shove the entire thing off to the right
side of the screen.
This adds a configuration item to the app settings, with a default
value of ';'.
This adds a new data format option, "binary include", that takes a
filename operand. When assembly sources are generated, the section
of file is replaced with an appropriate pseudo-op, and binary files
are generated that hold the file contents. This is a convenient way
to remove large binary blobs, such as music or sound samples, that
aren't useful to have in text form in the sources.
Partial pathnames are allowed, so you can output a sound blob to
"sounds/blather.bin". For safety reasons, we don't allow the files
to be created above the project directory, and existing files will
only be overwritten if they have a matching length (so you don't
accidentally stomp on your project file).
The files are not currently shown in the GenAsm dialog, which lets
you see a preview of the generated sources. The hex dump tool
can do this for the (presumably rare) situations where it's useful.
A new regression test, 20300-binary-include, has been added. The
pseudo-op name can be overridden on-screen in the settings.
We don't currently do anything new for text/HTML exports. It might
be useful to generate an optional appendix with a hex dump of the
excised sections.
(issue #144)
Note that address region isolation doesn't prevent explicit label
references from working (add update the test to prove it).
Added a note about pre-label xrefs.
If an address resolves to a user label in an isolated region, we
don't want to use it. However, we still want to try to match it
to a project/platform symbol.
For example, suppose the isolated code wants to reference address
$1C00, which is a memory-mapped I/O location in one area, but a
regular bunch of code in the other. We don't want it to map to
the regular code, but we do want it to resolve to our table of
platform I/O addresses.
We now handle this correctly. The regression test has been updated
to check this. The current implementation does a linear scan through
the symbol table, but I'm hoping this is not a common situation.
The reference manual has been updated to describe the new feature.
Added an address-to-offset test in the GeneratePlatformSymbolRefs()
method, which sets the operand symbols for anything that lands outside
the scope of the file. Because the region isolation code prevented
symbols from being associated with the operands in the initial code
scan, those operands were being examined here. Without the additional
test, the inappropriate label associations were getting a second chance.
Added "[!in]" and "[!out]" to the comment field of .addrs lines. This
is only for the on-screen display and text exports, not asm gen.
Bumped the project file CONTENT_VERSION.
Added a regression test (20290-region-isolation).
The test turned up an existing problem: pre-labels are emitted by the
asm generators on their own line, but the code that puts excessively
long labels on a separate line wasn't taking that into account. This
has been fixed. No changes to existing regression tests, which didn't
happen to use long labels.
We currently have two options for assembly code output, selected by
a checkbox in the application settings: always put labels on the same
lines as the instruction or data operand, or split the labels onto
their own line if they were wider than the label text field.
This change adds a third option, which puts labels on their own line
whenever possible. Assemblers don't generally allow this for variable
assignment pseudo-ops like "foo = $1000", but it's accepted for most
other situations. This is a cosmetic change to the output, and will
not affect the generated code.
The old true/false app setting will be disregarded. "Split if too
long" will be used by default.
Added test 20280-label-placement to exercise the "split whenever
allowed" behavior.
The "export" function has a similar option that has not been updated
(for no particular reason other than laziness).
Also, simplified the app settings GetEnum / SetEnum calls, which
can infer the enumerated type from the arguments. This should not
impact behavior.
If an end-of-line comment ended with '\', the code that "prettifies"
the JSON output would get confused, and would start inserting \r\n
after commas inside comment strings. This didn't corrupt the project
files, but it did make them look funny, and required manual cleanup.
Added a sample. This won't catch regressions of this particular
problem because it only happens when you save the file, but if
nothing else it'll act as documentation.
The implementation was mapping labels to addresses, then formatting
inline data at the matching address. This may be incorrect when there
are multiple sections of the file mapped to the same address. The
correct approach is to record the offsets of the matching labels, and
then do an address-to-offset translation for each JSR.
Also, show a note in the Info window when a JSR has been marked
no-continue by an extension script.
Also, updated Daily Tips.
We allow empty lines and lines that begin with ';' in .sym65. Lines
with nothing but whitespace, or comments with leading whitespace,
caused a warning. It can be aesthetically nice to line up the start
of comments, and lines with pointless whitespace aren't problematic,
so we now allow these without complaint.
Added some samples to the 20170-external-symbols data file. No
change to the test output.
The ACME assembler gets upset if you use "not" as a label. We now
avoid doing so, using a generalized implementation of the opcode
mnemonic rename code. (Issue #112.)
Renamed a label to "not" in the 20081-label-localizer test.
This allows regions that hold variable storage to be marked as data
that is initialized by the program before it is used. Previously
the choices were to treat it as bulk data (initialized) or junk
(totally unused), neither of which are correct.
This is functionally equivalent to "junk" as far as source code
generation is concerned (though it doesn't have to be).
For the code/data/junk counter, uninitialized data is counted as
junk, because it technically does not need to be part of the binary.
Added support for "relative" address regions to the Merlin 32 and cc65
code generators. These generate "flat" address directives, and so
were a little more complicated.
Suppressed generation of relative operands for non-addressable regions.
Also, tweaked the 20250-nested-regions test to include a negative
relative region offset.
Modified "jump to" code to understand address range start/end lines.
If there are multiple starts or ends at the same offset, we jump to
the first one in the set, which is suboptimal but simpler to do.
Simplified the API, embedding GoToMode in the Location object (which
is where it really needs to be, to make fwd/back work right).
Updated HTML export to grey out addresses in NON_ADDR sections.
Changed default pseudo-op strings for address regions to ".addrs" and
".adrend", after trying a bunch of things that were worse. Added
definitions for region-end pseudo-ops to Merlin32 and cc65 for display
on screen.
Added regression test 20260 for address region pre-labels.
Fixed handling of leading underscores in platform/project symbols.
These need to be escaped in 64tass output. Updated regression test
20170-external-symbols to check it.
Implemented "is relative" flag. This only affects source code
generation, replacing ".arstart <addr>" with ".arstart *+<value>".
Only output by 64tass and ACME generators.
Added a bold-text summary to radio buttons in address region edit
dialog. This makes it much easier to see what you're doing. Added
a warning to the label edit dialog when a label is being placed in
a non-addressable region.
Modified double-click behavior for .arstart/.arend to jump to the
other end when the opcode is clicked on. This matches the behavior
of instructions with address operands.
Reordered Actions menu, putting "edit operand" at the top.
Fixed AddressMap entry collision testing.
Fixed PRG issue with multiple address regions at offset +000002.
Added regression tests. Most of the complicated stuff with regions
is tested by unit tests inside AddressMap, but we still need to
exercise nested region code generation.
Split ".org" into ".arstart" and ".arend" (address range start/end).
Address range ends are now shown in the code list view, and the
pseudo-op can be edited in app settings. Address range starts are
now shown after notes and long comments, rather than before, which
brings the on-screen display in sync with generated code.
Reworked the address range editor UI to include the new features.
The implementation is fully broken.
More changes to the AddressMap API, putting the resolved region length
into a separate ActualLength field. Added FindRegion(). Renamed
some things.
Code generation changed slightly: the blank line before a region-end
line now comes after it, and ACME's "} ;!pseudopc" is now just "}".
This required minor updates to some of the regression test results.
This is the first step toward changing the address region map from a
linear list to a hierarchy. See issue #107 for the plan.
The AddressMap class has been rewritten to support the new approach.
The rest of the project has been updated to conform to the new API,
but feature-wise is unchanged. While the map class supports
nested regions with explicit lengths, the rest of the application
still assumes a series of non-overlapping regions with "floating"
lengths.
The Set Address dialog is currently non-functional.
All of the output for cc65 changed because generation of segment
comments has been removed. Some of the output for ACME changed as
well, because we no longer follow "* = addr" with a redundant
pseudopc statement. ACME and 65tass have similar approaches to
placing things in memory, and so now have similar implementations.
If a DCI string ended with a string delimiter or non-ASCII character
(e.g. a PETSCII char with no ASCII equivalent), the code generator
output the last byte as a hex value. This caused an error because it
was outputting the raw hex value, with the high bit already set, which
the assembler did not expect.
This change corrects the behavior for code generation and on-screen
display, and adds a few samples to the regression test suite.
(see issue #102)
On the 65816, if you say "JSR foo" from bank $12, but "foo" is an
address in bank 0, most assemblers will conclude that you're forming
a 16-bit argument with a 16-bit address and assemble happily. 64tass
halts with an error. Up until v1.55 or so, you could fake it out
by supplying a large offset.
This no longer works. The preferred way to say "no really I mean to
do this" is to append ",k" to the operand. We now do that as needed.
I didn't want to define a new ExpressionMode for 64tass just to
support an operand modifier that should probably never actually get
generated (you can't call across banks with JSR!), so this is
implemented with a quirk and an op flag.
64tass v1.56.2625 is now the default.
(issue #104)
The DCI string format uses character values where the high bit of the
last byte differs from the rest of the string. Usually all the high
bits are clear except on the last byte, but SourceGen generally allows
either polarity.
This gets a little uncertain with single-character strings, because
SourceGen can't auto-detect DCI very effectively. A series of bytes
with the high bit set could be a single high-ASCII string or a series
of single-byte DCI strings.
The motivation for allowing them is C64 PETSCII. While ASCII allows
"high ASCII" as an escape hatch, PETSCII doesn't have that option, so
there's no way to mark the data as a character or a string. We still
want to do a bit of screening, but if the user specifies a non-ASCII
character set and the selected bytes have their high bits set, we
want to just treat the whole set as 1-byte DCI.
Some minor adjustments were needed for a couple of validity checks
that expected longer strings.
This adds some short DCI strings in different character sets to the
char-encoding regression tests.
(for issue #102)
64tass wants to place its output into a 64KB region of memory,
starting at the address "*" is set to, and continuing without
wrapping around the end of the bank. Some files aren't meant to be
handled that way, so we need to generate the output differently.
If the file's output fits nicely, it's considered "loadable", and
is generated in the usual way. If it doesn't, it's treated as
"streamable", and the initial "* = addr" directive is omitted
(leaving "*" at zero), and we go straight to ".logical" directives.
65816 code with an initial address outside bank 0 is treated as
"streamable" whether or not the contents fit nicely in the designated
64K area. This caused a minor change to a few of the 65816 tests.
A new test, 20240-large-overlay, exercises "streamable" by creating
a file with eight overlapping 8KB segments that load at $8000.
While the file as a whole fits in 64KB, it wouldn't if loaded at
the desired start address.
Also, updated the regression test harness to report assembler
failure independently of overall test failure. This makes it easier
to confirm that (say) ACME v0.96.4 still works with the code we
generate, even though it doesn't match the expected output (which
was generated for v0.97).
(problem was raised in issue #98)
The initial implementation was testing the byte value rather than
the converted value, so backslashes were getting through in high
ASCII strings. PETSCII and C64 screen codes don't really have a
backslash so it's not really an issue there.
The new implementation handles high ASCII correctly. The various
201n0-char-encoding-x regression tests have been updated to verify
this.
Two things changed: (1) string literals can now hold backslash
escapes like "\n"; (2) MVN/MVP operands can now be prefixed with '#'.
The former was a breaking change because any string with "\" must
be changed to "\\". This is now handled by the string operand
formatter.
Also, improved test harness output. Show the assembler versions at
the end, and include assembler failure messages in the collected
output.
Code generated by one of the C compilers sets up the stack frame and
then maps the direct page on top of it. If the value at the top of
the stack is 16 bits, it will be referenced via address $ff. The
local variable editor was regarding this as illegal, because lvars are
currently only defined for direct page data, and the value doesn't
entirely fit there (unless you're doing an indirect JMP on an NMOS
6502, in which case it wraps around to $00... but let's ignore that).
The actual max width of a local variable is 257 because of the
possibility of a 16-bit access at $ff.
Older versions of SourceGen don't seem to have an issue when they
encounter this situation, as worrying about (start+width) is really
just an editor affectation. The access itself is still a direct-page
operation. You won't be able to edit the entry without reducing the
length, but otherwise everything works. I don't think there's a need
to bump the file version.
Added a compiled C implementation of strlen(). The most interesting
part about this is that it references a 16-bit value via direct-page
address $ff, which means you'd want a local variable with
address=$ff and width=2. The current UI prevents this.
The calculations were wrong for certain situations, generating
answers that were useless or that caused a false-positive overflow
error.
This adds a couple of simple regression tests, modeled after layout
of the Lode Runner sprite sheet (which worked fine before) and the
Empire II EWS3 font (which failed).
This also bumps up some of the arbitrary limits in the visualizer.
(issue #94)
The test for max allowed value was assuming 16-bit addresses.
We had no tests for 24-bit values, so this adds a 65816-specific
version of 20170-external-symbols.
Generate a 6502 test from the 65816 version by substituting the
16-bit instructions with 8-bit no-ops. There's a lot of project
edits and weird stuff in the test, so this was much easier than
starting over.
The 65816 variant is largely unchanged, though it could now be
stripped down to the stack-offset instructions.