aboutsummaryrefslogtreecommitdiff
Commit message (Collapse)AuthorAgeFilesLines
...
* Add a new 'check' stage in assemble()Miquel Sabaté Solà2026-04-302-108/+108
| | | | | | | | This is actually an expansion from asan(), but it also checks for stuff that goes outside of the realm of address sanitation. In this aspect, asan() has been integrated inside of the new check() function. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Send an error for unused .proc'sMiquel Sabaté Solà2026-04-285-42/+111
| | | | | | | | | | | | | | | | | We cannot safely detect all scenarios in which there is dead code, but we can safely do it for .proc's. Even if they are not called directly, they might be referenced via jump tables and shenanigans like that. Long story short, if you are not referencing a .proc in any meaningful way, then we have dead code. A pattern could also be given in which a function that was too long has been splitted into smaller functions which are not called directly. This is, in my opinion, an anti-pattern (as we generally expect an rts or a jmp from .proc's), and anyways can be avoided via the use of __fallthrough__ if the programmer is really set to write this kind of code. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* nasm: add documentation on the exit status codeMiquel Sabaté Solà2026-04-281-0/+9
| | | | | | | I apparently never bothered to do so. It's a good idea to have this as it might not be all that expected. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* nasm: call exit() right after error detectionMiquel Sabaté Solà2026-04-281-90/+88
| | | | | | | | The 'if error_count == 0' branch came from old code that accumulated over and over. Since this was the only branch taken before exit, let's prefer the other way around so we can remove one indentation level. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* nasm: use buffered writing for full ROMs as wellMiquel Sabaté Solà2026-04-281-4/+8
| | | | | | | | This was already implemented for the --split-segments option. Not let's bring this when building full ROM files, as writing things byte by byte is slow. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* nasm: avoid an unnecessary loop when writing bytesMiquel Sabaté Solà2026-04-281-5/+3
| | | | Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* nasm: add the --split-segments optionMiquel Sabaté Solà2026-04-282-33/+81
| | | | | | | | | | | | This allows the programmer to tell nasm to leave each segment into its own .out file. This can be useful when writing some specific segments into different chips. The caveat is that filling is not applied, and hence it's up to the programmer to account for that if two or more segments happened to be on the same mapping and needed some alignment in between. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* nasm: add a description on the README.md fileMiquel Sabaté Solà2026-04-251-0/+14
| | | | Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* tests: update submodules to their latest commitsMiquel Sabaté Solà2026-04-253-0/+0
| | | | Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Add the context's name into memory rangesMiquel Sabaté Solà2026-04-252-4/+8
| | | | | | | | This is applied whenever a given memory range name is not under the global context. The end result is that scopes will be shown into the memory.txt file when using '--write-info'. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Add the .min and the .max control expressionsMiquel Sabaté Solà2026-04-243-0/+91
| | | | Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Allow scoped names in __fallthrough__Miquel Sabaté Solà2026-04-243-1/+11
| | | | | | Fixes 4f1a9c660108 ("Add the .fallthrough control statement") Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Add a big endian control statementMiquel Sabaté Solà2026-04-243-5/+73
| | | | | | | | | | | By default everything is little endian, and that should always be the case. That being said, if a literal is better expressed in big endian format for whatever reason, you can now use the .be or the .bigendian control statements. The terribly named .dbyt control statement can also be used for this purpose, but that's just to be compatible with the implementation from ca65. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Add the .version pseudo-variableMiquel Sabaté Solà2026-04-243-0/+45
| | | | Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* ci: upgrade to actions/checkout@v6Miquel Sabaté Solà2026-04-241-5/+5
| | | | | | | This fixes a deprecation warning on an outdated Node.js version being used. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Update the code style to the latest stable RustMiquel Sabaté Solà2026-04-244-22/+15
| | | | | | | | | | This mostly involves applying the collapsible_match rule[1] where appropiate, and using sort_by_key() as pointed out by the latest stable version of clippy. [1] https://rust-lang.github.io/rust-clippy/rust-1.95.0/index.html#collapsible_match Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* tests: add jetpac.nes to the end-to-end testsMiquel Sabaté Solà2026-04-243-0/+23
| | | | Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Fix outdated comment on __fallthrough__Miquel Sabaté Solà2026-04-241-4/+4
| | | | | | | | | | Since commit 31dd071e927a ("Change .fallthrough to __fallthrough__") this pseudo control statement is declared via underscores, not like a proper control statement. That was done in order to avoid clashes with ca65, and in order to allow nasm's --prelude to produce a .macro replacement for it when using ca65. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Fix calls with arguments containing addressesMiquel Sabaté Solà2026-04-241-1/+46
| | | | | | | | | | | | | | | | | | | | | | | | | Some macro calls could contain addresses, like this: MACRO_CALL @address Before this commit this was resolved at the "crunch" stage, but only because we were grabbing the value from the part that was not resolved. However, if this unresolved object came from a node which is not just a value (e.g. an arithmetic operation), then it just applied the computation from before the "crunch" stage. So, for something like this: MACRO_CALL @address + 1 the argument would have been computed as simply "1", as that unresolved object only contained the "+ 1" known part. Fix this by re-evaluating the node at "crunch" stage whenever we have an attached "node" member to the given pending definition. This way, we can evaluate the full node and get the proper value from the arithmetic computation. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Ensure expressions in arguments are fully parsedMiquel Sabaté Solà2026-04-232-0/+33
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | Imagine the following scenario: lda #.lobyte(@address + 1) Here we have an immediate which comes from the .lobyte call. That being said, since this is using the '#' symbol, we look ahead after noticing it just in case we need to disambiguate some scenarios. When a parenthesis is found, in extract_paren_expression() we temporarily discard the looking ahead status as expressions inside of parenthesis are no longer affected by any hypothetical external ambiguity. This, though, was not being done in parse_arguments(), which is the function that would be called in the above scenario. Hence, ensure that we temporarily decrease the look ahead status for the inner arguments, and then increase it back when we are done. This way, when the parser finds '@address', it will no longer go the "we have found a 'value', refrain from ambiguities and return early" route, and it will check for any binary expression. Note that all this dance actually applied here, as binary operations are a source of ambiguities, and the look ahead mechanism was brought about because of these kinds of expressions. Hence, it's not like the look ahead mechanism is troublesome in on itself, we just missed the special handling on this specific scenario. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* xa65: fix indentation on the help messageMiquel Sabaté Solà2026-04-231-3/+1
| | | | Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Add documentation for asan:stackMiquel Sabaté Solà2026-04-081-0/+23
| | | | Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Implement the asan:stack statementMiquel Sabaté Solà2026-04-0813-7/+348
| | | | | | | | | | | | | | This statement allows programmers to reserve a memory range for the stack. This is useful to reserve a memory region which is not attached to any variable, and: 1. It is a way to safely reserve space on the $0100 page. 2. The --stats/--write-info flags will be able to add up the memory space reserved for the stack. 3. Future tooling might be able to use this value as a way to detect stack overflows. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Re-create the values for bundle call argumentsMiquel Sabaté Solà2026-03-105-4/+94
| | | | | | | | | | | | | | | | | | Bundle call arguments were fine most of the times, when arguments could be processed as-is and there were no issues with arguments being overwritten by successive calls. This was not the case, though, whenever a given instruction was delayed into a PendingNode status. In this case, the argument would get the last value, and in some extreme cases that definition might not have been there any more. Prevent all of this by providing a list of PendingDefine's, which are a way to re-create these call-only arguments as they were initially found. These PendingDefine's are then created on "crunch" on each PendingNode. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Ignore GLOBAL_CONTEXT on force_context_switch()Miquel Sabaté Solà2026-03-091-0/+6
| | | | Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* asan: ignore names from macro argumentsMiquel Sabaté Solà2026-03-093-5/+19
| | | | | | | These are usually capitalized, and thus they are not going to be following the usual zp_/m_/wr_ pattern. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Fix small typoMiquel Sabaté Solà2026-02-271-1/+1
| | | | Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Define the global scope to a more obscure nameMiquel Sabaté Solà2026-02-251-1/+1
| | | | | | | | | | | | | | | By how we define scopes, we needed an internal name for the global scope. All the way back to my first commit 587dd5bb8036 ("Initial commit"), I simply picked "Global". That is troublesome, as it can easily be typed by a human. If a programmer writes a scope with "global" definitions via this scope, this can be messed up with nasm's internal Global scope. Change that to a more obscure name for this internal global scope. If a programmer is so dead from the inside that wants to have a scope named like that, so be it. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Fix small indentation typoMiquel Sabaté Solà2026-02-251-1/+1
| | | | Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Raise an error when a control statement does not existMiquel Sabaté Solà2026-02-251-11/+10
| | | | | | | | | In this case it was silently letting it go in the hopes that the assembler would catch it, but it's better to just handle it in the parser and give a proper error instead of complicating the assembler a bit more. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Allow using a byte for indirect jumpsMiquel Sabaté Solà2026-02-115-11/+37
| | | | | | | They should be expanded to a 16-bit address from the zero-page. The fact that the assembler was complaining about it was simply erroneous. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* asan: Fix validation on indirect jumpsMiquel Sabaté Solà2026-02-112-3/+2
| | | | | | | | | | | | | | There were two bugs involved at the same time. First, for some reason, the "matches" clause was negated, which defeats the purpose of the check. This even resulted in a bad test run which was accepted because I just did not caught it before. Second, pure indirect addressing mode is only available for the "jmp" instruction. Hence, there's no need for that "matches" at all, and even less to filter that based on "jsr" which doesn't even implement this addressing mode. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* asan: don't complain on arithmetic with addressesMiquel Sabaté Solà2026-02-063-6/+20
| | | | | | | This was already the case for plain addresses, but it was not being considered in the case of an arithmetic operation. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Fix the arithmetic on indexed addressing modesMiquel Sabaté Solà2026-02-051-51/+136
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | In instructions like: lda address + 1, x The assembler was picking the size from the "+ 1" side, making this part of a one-byte size and, hence, assuming it was zeropage indirect addressing instead of an absolute one. This meant that one byte was cut off the end binary, and the address was wrong altogether. Fix this by telling the assembler to assume a .size = 2; for variables which have been defined as addresses. Then, the operation evaluation can take that as an indication to set the size to 2 as well and, hence, assume absolute indirect addressing. Moreover, this bug was intertwined with another one, where arithmetic could be borked when both operands were of an unexpected size. For example: lda #(300 - 260) Here the size would've been resolved to 2 as well, but it would have also reported an error because both operands were 2-bytes long, despite the end result fitting on a single byte. Since this is an explicit immediate addressing, then it would have assumed the programmer to try that with a 16-bit value, which is wrong. This commit also fixes this bug as it was deeply intertwined to how numbers are computed on operations and how sizes are evaluated. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Document the __NASM__ and __fallthrough__ featuresMiquel Sabaté Solà2026-02-031-0/+138
| | | | Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* nasm: improve message on the -D flagMiquel Sabaté Solà2026-02-031-1/+3
| | | | Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Make the fallthrough error more explicitMiquel Sabaté Solà2026-02-032-4/+7
| | | | | | | Add the target and effective addresses into the message, so it's more clear how different they are. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Add __NASM__ protection on the --prelude outputMiquel Sabaté Solà2026-02-031-3/+5
| | | | | | | | The __fallthrough__ macro can only be done when using ca65, not nasm, as that's a protected identifier. Hence, wrap the __fallthrough__ macro definition via an .ifndef __NASM__. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Avoid invalid identifiers in proc/macro/scopeMiquel Sabaté Solà2026-02-035-7/+81
| | | | | | | | This was apparently neglected and you were able to pick invalid identifiers to identify procs, macros and scopes. Ensure this does not happen again and provide tests for it. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Ensure __fallthrough__ is not considered a valid identifierMiquel Sabaté Solà2026-02-031-1/+4
| | | | Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* nasm: add the --prelude flagMiquel Sabaté Solà2026-02-021-0/+18
| | | | | | | This flag prints to the standard output some helper code that bridges nasm-exclusive features with ca65. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Change .fallthrough to __fallthrough__Miquel Sabaté Solà2026-02-026-46/+57
| | | | | | | | | | | | | Implementing it as a control statement has the bad thing that it's impossible to be compatible with other assemblers such as ca65, as you cannot create dummy control statements or something like that in there. Instead of that, we define it with the special underscores which are still valid for identifiers, and give a "compiler-specific thingie" flair to it. This also has the benefit that the parser can be a bit more strict. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Fix typo in commentMiquel Sabaté Solà2026-02-021-1/+1
| | | | Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Add the .fallthrough control statementMiquel Sabaté Solà2026-02-029-1/+164
| | | | | | | | | | | | | | | | This is exclusive to 'nasm' and it allows the developer to explicitly tell the assembler than a "fall through" condition is actually desired: it's not a mistake. This comes in two flavors. The first, without arguments, just makes this explicit without much enforcement. The second allows you to pass an argument which is the name of the function or label you are expecting to fall through. The assembler will error out if the fall through address is not the expected one, hence telling the programmer whenever the fall through condition they thought in the past is no longer true (e.g. the function has moved somewhere else in the code). Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* nasm: define the __NASM__ variableMiquel Sabaté Solà2026-02-021-0/+3
| | | | | | | This variable is defined by default in nasm and it can be used for assembler compatibility code. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* xa65: add -Werror to the --strict flagMiquel Sabaté Solà2026-02-021-1/+1
| | | | Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Warn on pointless (un)conditional branchingMiquel Sabaté Solà2026-02-026-0/+116
| | | | | | | | | | | | | | | | | | | | | | | | | | Sometimes performing some 'jmp'/'jsr' can be quite pointless, and the programmer might not be fully aware of this because of the layout of the code. Imagine: .proc foo ;; code jmp bar .endproc ;; Documentation, comments, extra space, etc. .proc bar ;; whatever .endproc The 'jmp' in the code above tries to perform a call stack optimization, but it's actually not needed because the next instruction after 'jmp' is the one inside of 'bar', but that's obfuscated because of the layout. In these sort of cases (and also for 'jsr' and branches) warn the programmer about it so it can remove that instruction. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* xixanta: add context from macro expansionsMiquel Sabaté Solà2026-02-023-4/+163
| | | | | | | | | | | | | The way macro expansions work is that the evaluated bundles replace the current node, but this throws away the context of the line, the source, etc. from the original line of code. Add a stack that is pushed/popped when expanding macros, and are then cloned for each pending node and error. This way, errors have full context of the original code and can display backtraces for macro expansion. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* tests: do not generate dummy out.nes filesMiquel Sabaté Solà2026-02-021-3/+3
| | | | | | | | For tests which the resulting binary is not needed, redirect the output (i.e. the ROM file) to /dev/null. This way we don't litter the workspace with dummy out.nes files. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
* Fix -a/--asan flag parsingMiquel Sabaté Solà2026-02-021-1/+1
| | | | | | Fixes: 8e7993a63e32 ("assembler: Add support for asan:reserve,ignore"). Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>