aboutsummaryrefslogtreecommitdiff
path: root/lib/xixanta
Commit message (Collapse)AuthorAgeFilesLines
* xixanta: Don't allow negative variables on asanMiquel Sabaté Solà2025-09-121-4/+41
| | | | | | | | | | | | | | Negative variables make no sense when it comes to do stuff like: variable = -1 lda variable That being said, as an assembler you never know the hacks and nonsense programmers are willing to endure. But we do know that if the address sanitizer is enabled, since if it's an "asan-friendly", then an explicit negative variable can be barred. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* asan: Add fixes on absolute/indirect addressingMiquel Sabaté Solà2025-09-031-1/+6
| | | | | | The check was not being applied on certain conditions. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Apply asan:ignore also when bundlingMiquel Sabaté Solà2025-09-031-1/+13
| | | | | | | This way instructions which might make use of bare memory numbers can freely ignore the address sanitizer when it actually makes sense. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Add a check for variable namesMiquel Sabaté Solà2025-09-031-0/+67
| | | | | | | This check ensures that asan-friendly names actually match their expected scope. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Validate that memory access is done via variablesMiquel Sabaté Solà2025-09-032-9/+157
| | | | | | | | | | | | | The address sanitizer is now able to detect whenever in an instruction a memory access is done without using variables. This is now detected for all instructions except for branching, which falls outside of this scope. Moreover, simple arithmetics is allowed and bounds are checked for simple cases. That being said, more involved bound checks should be done with other tools (e.g. emulators). Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Add a warning for each unused variableMiquel Sabaté Solà2025-09-022-31/+67
| | | | Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* assembler: Preserve the original working directoryMiquel Sabaté Solà2025-09-021-0/+10
| | | | Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* parser: Allow .include inside of .scopeMiquel Sabaté Solà2025-09-021-6/+21
| | | | Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* parser: Avoid unwrap crash on weird quoted stringsMiquel Sabaté Solà2025-09-021-1/+1
| | | | Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* assembler: Add support for asan:reserve,ignoreMiquel Sabaté Solà2025-09-026-96/+391
| | | | | | | | This is the initial support for both directives for the address sanitizer. Note that asan:weak has been moved into asan:ignore, which is not exactly the same but for now it should suffice. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* parser: Add asan:reserve and asan:weak supportMiquel Sabaté Solà2025-08-282-19/+223
| | | | | | | | | | These are special directives that happen on comments, and hence this parser will no longer simply ignore comments. This feature is not used by the assembler, but following commits should build up address sanitizer strategies from it. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* nasm: Error out when using WRAM when not availableMiquel Sabaté Solà2025-08-281-0/+26
| | | | | | | | | | This commit introduces the ability to inspect the temptative header before producing the actual output, and with that it checks whether the Working RAM is being advertised or not. If it is not being advertised but the assembler detected memory accesses to that region, then we are in trouble and we should error out. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* xixanta: Be more mindful on what's being exportedMiquel Sabaté Solà2025-08-271-6/+21
| | | | | | | This means removing a lot of `pub` structs or enums, as well as adding documentation on `pub` structs. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* nasm: Implement the -s/--stats optionMiquel Sabaté Solà2025-08-271-0/+9
| | | | | | | | This option prints further information on how segments are laid out. In particular, for now it prints the amount of space being filled for each segment. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Don't get into all blocks when evaluating the contextMiquel Sabaté Solà2025-08-181-4/+51
| | | | | | | | For some control statements like .if/.ifdef/.ifndef this is only desired when the condition is true; otherwise getting into the inner block should be prevented. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Provide a node to the Object structMiquel Sabaté Solà2025-08-182-1/+75
| | | | | | | | | This allows the `evaluate_variable` to pull from it in the crunching stage so to evaluate the original node in cases like macro expansion, where the connection between the macro argument and the original caller might have been lost. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Reset literal mode before left arm of an operationMiquel Sabaté Solà2025-08-181-0/+5
| | | | | | | | On an arithmetical/logical operation, the literal mode needed to be reset before evaluating the left arm since the previous evaluation of the node could have altered it. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Include RODATA inside of the default nrom65 configMiquel Sabaté Solà2025-08-181-1/+1
| | | | | | | | This is really not needed from my point of view, but some existing code makes use of this and so it is actually useful to have it in the default configuration. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* xixanta: Allow for mapping size larger than 16 bitMiquel Sabaté Solà2025-08-181-3/+10
| | | | | | | In configuration files, the 'size' attribute can actually be larger than a 16-bit value, and that is fine inside of the ROM layout. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Fix shift overflow on certain expressionsMiquel Sabaté Solà2025-08-181-2/+2
| | | | | | | | | I got a report from libfuzz that some cryptic input could make the assembler panic on shifts. It turns out that the check on whether the operator was too big or not had to be explicitely casted to `usize` to avoid signedness issues. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Use a buffered reader for incbinMiquel Sabaté Solà2025-08-171-2/+3
| | | | | | | | | Iterating via `bytes()` on a file is inefficient as the default implementation calls `read` on each byte, which can be costly on bytes which are not in memory like files. This is extra important for statements like `incbin` as included files can be rather big. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Apply suggested style fixes from clippyMiquel Sabaté Solà2025-08-176-64/+46
| | | | Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* parser: Fix disambiguation paren on first argumentMiquel Sabaté Solà2025-08-171-3/+99
| | | | | | | | | | | | | | | | | | | Arguments can be put inside of enclosing parenthesis, but the parser was assuming that if an opening paren was found when parsing the first argument on an argument list, then that was all it was needed to be parsed. This though conflicts with situations like: .byte ($01 << 2) | ($01 << 1) In this case, the parser would have ignored everything past the first closing paren. This commit provides a fix in which if an operation is found past the first enclosing parenthesis, then this assumption is discarded in favor of a parenthesis being used for disambiguating on an arithmetical/logical expression. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Add a configuration for MMC1Miquel Sabaté Solà2025-01-232-0/+10
| | | | Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Add support for a single equal sign operatorMiquel Sabaté Solà2025-01-231-1/+4
| | | | Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Drop lazy_static dependencyMiquel Sabaté Solà2025-01-224-489/+1703
| | | | | | | Apparently the standard library had LazyLock which is enough for what I wanted to achieve with lazy_static. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Implement echo control statementsMiquel Sabaté Solà2025-01-223-2/+48
| | | | Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* nasm: Implement the -D flagMiquel Sabaté Solà2025-01-222-5/+65
| | | | | | | This allows users to define variables directly from the command line, which is useful for testing purposes. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Remove dependency on TOMLMiquel Sabaté Solà2025-01-2212-413/+121
| | | | | | | | | | | | | | | | | | | When I introduced this dependency it looked like a good idea to have a better-looking replacement to cl65's cfg format. That being said, the end result wasn't *much* prettier either, and the end result could be even bigger and equally confusing. Since 5f48de69f46d ("Add support for cfg files") there is quite the framework in order to support regular cl65's cfg files. Hence, this commit takes another approach: let's tune this format to a more compressed and simplified one. This is now the current "nasm cfg" format, and it allowed us to re-use a lot of code while also being more to the point for NES/Famicom development than the original cfg format. With this new format, we can now remove the dependency on TOML and all of the inner dependencies which were quite a lot. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Remove dependency to the rand crateMiquel Sabaté Solà2025-01-223-94/+10
| | | | | | | | This dependency was easily avoidable and it brought with it a lot of inner dependencies of its own, most notably 'zerocopy-derive', which forbid us to compile the affected programs purely statically. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Be more explicit on empty identifiersMiquel Sabaté Solà2025-01-211-6/+3
| | | | | | | If the programmer only wrote a single special character for an identifier, then we will consider it empty to avoid shenanigans. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Allow dot characters on identifiersMiquel Sabaté Solà2025-01-211-19/+67
| | | | | | | | In fact, they were always allowed, but they were in kind of grey area, as they could be defined but not used, and sometimes they could be used in the middle of identifiers, which was unexpected. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Introduce looking ahead when parsing literalsMiquel Sabaté Solà2025-01-212-193/+296
| | | | | | | | | | | | | | | | | | | | | | There were certain situations in which syntax ambiguity could arise. For example, the parser as it stood could treat a valid expression such as 'lda #$80 >> 2' in an unexpected 'lda #$(80 >> 2)'. This is of course bad, and it came from the fact that literals don't have enclosing characters, and white spaces are not enough to provide disambiguation in some cases. Because of this fact, the parser now has a "look ahead" capability similar to many other parsers, and it's applied for now only to literals. This looking ahead actually honors parenthesis, so these can be added if the programmer wants to explicitely disambiguate an expression. This involved quite the heavy lifting, and some functions like 'parse_expression_with_identifier' had to be removed with the rewrite. This had the side effect of having (hopefully) more sane functions all around, and the parser also has a better capability to differentiate between regular Values and Calls. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Track the level of recursive callsMiquel Sabaté Solà2025-01-201-18/+35
| | | | | | | | | This is in preparation to some heavy lifting that is to be done to the parser so it more properly handles nested expressions, but in general it's a good idea to have some limits to functions that expect to be called recursively quite heavily. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Whitelist valid identifier charactersMiquel Sabaté Solà2025-01-162-8/+27
| | | | | | | | Instead of making up a list of characters that end an identifier, do the other way around since it's far less cumbersome and it prevents from silly bugs such as "var+1" being considered a single identifier. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Permit 16-bit decimal valuesMiquel Sabaté Solà2025-01-161-9/+18
| | | | | | | | | | As a remnant of old code, the 'parse_decimal' function was not allowing for decimal values larger than 8-bits. This was not the case in other areas such as 'parse_hexadecimal', and in the rest of the code we already cover that immediates are not too big in instructions. Hence, this restriction can be lift up and allow up to 16-bit decimal literals. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Implement .ifdef/.ifndef statementsMiquel Sabaté Solà2025-01-164-4/+78
| | | | | | | They are just synonyms for ".if .defined" and ".if !.defined" respectively. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Implement .def/.defined expressionsMiquel Sabaté Solà2025-01-163-0/+57
| | | | | | | This can be combined with .if/.elsif statements just like any other expression. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Implement .if/.elsif/.else statementsMiquel Sabaté Solà2025-01-164-43/+258
| | | | Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Add boolean operatorsMiquel Sabaté Solà2025-01-163-11/+100
| | | | | | | | | | | Allow for expressions that evaluate to a boolean expression. This in turn mean that the value is just set to 0 or 1 depending on the given condition. As with other assemblers, only a value of 0 evaluates to 0, and others go to 1. So, something like "1 && 2" evaluates to 1 even if it doesn't make much sense at first glance (as an assembler we just assume that the programmer knows what it's doing). Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Fix error with strings containing equal operatorMiquel Sabaté Solà2025-01-151-10/+7
| | | | | | | | | | | As with e27a1593c8d8 ("Allow semicolons inside of strings"), the parser was too naive and regarded any '=' operator as part of an assignment, despite that it could be art of string literal. Luckily the fix was already done inside of the parsing of assignments, we just needed to move it up. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Allow semicolons inside of stringsMiquel Sabaté Solà2025-01-151-9/+43
| | | | | | | | | | | | The parser was too naive and assumed that a semicolon immediately implied an inline comment, and that might not just be the case as it is with string literals. Hence, the end of each semantic line has to consider not only whether there is an inline comment, but also if a string literal is being used and whether it surrounds or not the given semicolon. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Simplify string arguments for control statementsMiquel Sabaté Solà2025-01-152-28/+51
| | | | | | | | | | | Some control statements (e.g. '.incbin', '.asciiz') only require a double-quoted string as an argument. In fact, for these functions there's only one argument required, which is this string one. Given this fact, the parsing on these functions don't have to go through the (expensive) general argument parsing function, and they can simply assume that a double-quoted string will be provided. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Disambiguate unary/binary operatorsMiquel Sabaté Solà2025-01-151-1/+8
| | | | | | | Some operators like '<' and '<<' could be mistakingly be treated as the other. Let's remove this ambiguity when checking for unary operators. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Move check for ASCII-only strings into the parserMiquel Sabaté Solà2025-01-152-9/+6
| | | | Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Split 'parse_expression' into more functionsMiquel Sabaté Solà2025-01-151-70/+86
| | | | | | | | The other cases in which fetching an "identifier" is not needed were starting to pile up. Hence, split them into separate functions and allow 'parse_expression' to be more simple. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Parse a string literal as a single objectMiquel Sabaté Solà2025-01-151-0/+47
| | | | | | | | | Before this it was left to the `parse_identifier` to figure things out, but this was prone to silly errors like "a: b", in which it would mistake it as the start of a label. Instead of any of this, just consume a string literal if it has been detected. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Add .byt as a synonym for .byteMiquel Sabaté Solà2025-01-141-0/+1
| | | | | | Not that I like it, but there are existing code which already uses this. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Implement .asciiz control statementMiquel Sabaté Solà2025-01-143-10/+72
| | | | Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
* Implement the .res control statementMiquel Sabaté Solà2025-01-143-0/+100
| | | | | | | | | | | | | Similarly to other assemblers, this allows the programmer to write a definite amount of bytes with the same values. Compared to other assemblers there are two things to notice. First, there is a limit to it (i.e. whatever can fit in 2 bytes). Second, if the fill value is not provided, then it will default to the current mapping's fill value, or just 0x00 if the current mapping doesn't define one of its own. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>