| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
| |
They started with good intentions, but in the end they were all pretty
much alike. Hence, it makes sense to simplify everything and provide a
single struct.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
| |
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
This needed some heavy lifting when it comes to how files were located.
This means that statements like .include/.incbin now take into
consideration a new list made out of SourceInfo, which holds enough
information to translate from which file a node comes from. This has
also been added into errors, so they are more informative on what went
wrong.
In order to tests this, besides all the regular unit tests, a new e2e
test has been added.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
| |
In bad314e1cfbf ("Prevent numeric literals from having spaces") it was
added already the restriction on not having whitespace characters in
literal expressions. Here we go a step further and we more explicitely
limit which symbol combinations can go into a literal declaration (e.g.
"#$2" is valid but "##2" is not).
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
| |
It has been found that having literals like "# 20" can potentially be
troublesome and even introduce crashes. Hence, as it's done in other
assemblers, disallow this kind of syntax.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
| |
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Sometimes, out of clarity, the programmer may have written something
along the lines of:
lda $40, y
This is invalid because the `lda` instruction does not allow zeropage
y-indexing addressing mode. That being said, it does allow for absolute
y-indexing addressing mode. This commit allows this syntax by
transforming code like the previous one into:
lda $0040, y
This cannot always be done, but the assembler should at least try if
it's possible and not trouble the programmer.
That being said, this is otherwise a bit shady since the programmer
might think that it's a 2-byte instruction when it's a 3-byte one.
Hence, maybe a future linter can pick up code like this and suggest a
more explicit writing.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This is a control statement which acts similarly as .proc/.macro/.scope,
in which an inner block is allocated for it. Hence, all the previous
work from 1f8a6becc7cd ("parser: Implement block bodies") and
ec8b709fa24c ("Implement block bodies inside of the assembler") make
this one out possible, as .repeat statements don't have an identifier
that can be used for hashing.
From the parser perspective this introduction raises two new things.
First of all this control statement also needed a differentiation
between the amount of required arguments, and the allowed ones, since
there is a second optional argument to it. And second, even the
identifier is not given, we have to generate one so to add a context for
it. This was at first not needed, but introducing .repeat-only variables
means that we have to have inner contexts which need to be named somehow
so we can retrieve the context later when picking up the value for them
again.
This last thing brought the need for a new dependency: rand. This is
used to generate a random string to identify the .repeat block.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
It is not safe to store a node index for macros since the list of nodes
that is passed down during assembly might change depending on whether an
inner block is being evaluated. Hence, the previous implementation would
break on a simple macro call inside of a .proc.
This also raised some concerns on the design around the API, since the
lifetime of references for internal assembler data needed an explicit
lifetime now, and as a side-effect functions like `assemble` had to be
moved out of the inner impl Assembler. This is in retrospect also a
better design choice.
Fixes: ec8b709fa24c ("Implement block bodies inside of the assembler").
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
| |
The parsing of control statements have become more complex since the
introduction of block bodies in 1f8a6becc7cd ("parser: Implement block
bodies"); so it makes sense to move it into its own thing and keep
`parse_statement` more clear.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
| |
Following 1f8a6becc7cd ("parser: Implement block bodies"), the support
for the new way of managing block bodies have also been added into the
assembler.
There are still some things to iron out, but they will be fixed in later
commits.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
| |
These are bodies which are the right node of some proc controls. This
way the parser comes back to sanity for statements like .macro and the
likes, and behaves more like a usual parser. This was not done in the
past because I thought things could have been simpler this way, but it
ended up making the assembler way more complicated that it needed to.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
| |
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
| |
Instead of calling `evaluate_node` for each node on a macro, just call
`Assembler::bundle` for the list of nodes so the context is preserved
and labels and other statements can be catched as usual.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
| |
This is just prone to errors and it is confusing all around. Just
prohibit developers doing that.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
| |
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
| |
Prevent a missmatch on .end{macro,proc,scope}. This was more or less
already covered when there was a bad context_pop call, but it was prone
to errors.
Check this in eval_context as it should've always been done.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
| |
Force .segment and .macro statements to be on the global scope since
this is how they are meant. Hence, if the programmer tries to do this,
just error out.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
| |
This opens up the door for developers to pass their own configuration
files.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
| |
This will allow the creation of configuration files that can live
outside of this tree, so developers can fine tune configuration files of
their own without having to pick up whatever is currently available.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
| |
I have also added an end-to-end test for it.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
| |
Fixes: 8b5feeed96b3 ("assembler: Implement and add tests for operators")
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Commit ea5f0f81b8a7 ("Shrink some absolute instructions by one byte")
applied the optimization in all cases, but we cannot perform it on
bundles which are yet to be resolved. This is because in unresolved
bundles the value is only an offset, which usually will fit on a single
byte and hence the optimization would've been carried out. That being
said, whenever we resolve this it might just be the case the it wouldn't
have fit in that single byte, and hence we end up with an artificially
shrinked instruction for a 16-bit address.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
| |
Some instructions which make use of absolute addressing can actually be
further compressed to act like zeropage indexing. This can be done if
the immediate being used by that instruction can actually fit into a
single byte. If that's the case, we will then "correct" the programmer
by using zeropage indexing instead of an absolute one, thus reducing one
byte for that instruction.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
| |
It was weird to show warnings which also showed "Error: " as a message,
and likewise it was weird for errors to display their kind, since users
simply do not care about this kind of information.
Hence, streamline the format to something closer to what it's done by
modern assemblers/compilers.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
| |
Warnings are mere xixanta::error::Error's which are not pushed into the
Err of Result. That is, instead they are accumulated into an internal
`warnings` vector inside of Assembler.
On the binary side we now show warnings as well, and there is an option
to turn warnings into errors.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
| |
This is normal when calling the same macro multiple times and in which
parameter values need to be updated on each case.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
| |
If a given variable cannot be found on the current scope, attempt to go
up the context hierarchy to find it.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
| |
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
| |
This includes support for both binary and unary operators. Not all of
them as listed by ca65 have been moved in. Let's do that whenever it
make sense on each case.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
| |
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
| |
Some expressions might be enclosed with parenthesis in order to avoid
ambiguations when evaluating them. Account for this on the parser when
parsing expressions. Note that this is strictly only on the
`parse_expression` function; statements or other top level constructs
cannot be enclosed inside of parenthesis.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
| |
This also forced us to add the current working directory to the
`Assembler::assemble` public function, as otherwise this control
statement and others wouldn't know how to resolve relative paths.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
The handling of labels and proc's both when evaluating the context and
when bundling is almost identical. The only change is that proc's need
to change the context afterwards, but otherwise they need to create a
label just as regular ones.
Merge things as much as possible on both these cases, while also taking
the chance to do some much needed clean up around these areas, and
adding a bit of helpful comments in between.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
| |
Failing to do so would spill over the previous literal mode into the
evaluation of nodes pending to be crunched.
Fixes: a9f50efdef40 ("Fix label references on control statements")
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
| |
Up until now defining a proc only involved pushing/popping the context.
Here we also allow it to create a label so it can be referenced by
instructions like jsr.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
| |
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
| |
They were named with increasing numbers due to the fact that that's the
default behaviour from cargo fuzz's command. So, just rename them to
proper human-readable names.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
When evaluating binary literals we allowed the shift value to grow as
needed and we checked whether it was a good value after evaluating the
literal. This is bad for performance reasons: if we are expecting an
exact size for a literal (8 digits here), do not even attempt to do
anything at all if the size doesn't match.
Moreover, in some extreme cases this could result into an overflow of
the 'shift' variable, which was promptly catched by Rust's bound
checker.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
| |
Some of the functions are actually private, so don't export them.
Moreover, there was an import cycle which was not needed and was forcing
a public import. Remove that as well.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
| |
This function originally came from the naive idea I had with how
mappings and segments ought to work. For this reason, the function grew
more ever more complex.
Split this function into more clear responsabilities for each new
function.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
| |
These two enum values were actually never used and they are not relevant
for the assembling process. Let's remove it for simplicity's sake.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
| |
Fixes: 03dae41b2ec2 ("Prevent addresses which are out of bounds")
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
| |
In some bad scenarios addresses might be pointing out of bounds (e.g. a
reference further than 0xFFFF). This has to be avoided and through fuzzy
testing we even got Rust panics for out of bounds u16 arithmetic. Hence,
just go through usize for the actual computation and check with
u16::MAX.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
| |
Having a From<std::io::Error> came from a hacky beginning in which
std::io::Error was being abused. Now the error handling is saner, so
there's no more need for that.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
| |
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The readrom binary is similar to `readelf` from Linux and it will allow
to display information from an NES/Famicom ROM file. For now the
information being shown is just the header, but in the future we might
also include disassembling parts of the code, or retrieving the "CHARS"
section for a given ROM file, and similar.
In order to implement the header parsing part a new library has been
introduced, simply named "header" which abstracts everything away so you
just need to call `Header::try_from("my bytes")` to fetch the actual
information.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
| |
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
There was a big missunderstanding on how things were to be laid out in
the end file, and so it was needed to create a proper understanding on
what's a Mapping and what's a Segment. These turned out to be
fundamental concepts that I failed to grok up until this commit.
Hence, this commit re-arranges completely how variables and labels are
stored in the Context, and how these objects can then be translated into
bundles that can be spit out to the caller.
This commit, besides introducing the new Mapping struct, also introduced
a more general Object, which abstracts things from the Bundle struct,
and allows us to pass certain metadata about the bundle at hand.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
| |
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|