Arithmetic operations
Last updated
Last updated
At some point, you would probably want to increase RAM address $7E000F by $01, but a simple LDA and STA won't work, because this simply changes the RAM Address' contents to $01 – not increase it by one. Maybe you'd like to increase it by 2 instead, or even multiply by 2.
The SNES has a few instructions capable of doing basic math operations.
These are opcodes to increase or decrease a value by 1.
INC and DEC support both the accumulator as well as addresses. Here's an example of increasing the accumulator by 1:
Here's an example to decrease the accumulator by 1:
Here's an example to increase the value of an address by 1, without affecting the accumulator at all:
Here's also an example to decrease a value by one
There are also edge cases with these operations. When you use INC when the value that is being modified is currently $FF, it would result in a $00 and the zero flag being set. When you use DEC and the value that is being modified is currently $00, it would result in a $FF.
INC and DEC don't work with long addressing modes. They only work with absolute or direct page addressing modes. Therefore, instructions like INC $7E000F
do not exist. Instead, you should use INC $000F
or INC $0F
.
Why isn't there a long addressing mode? The processor is simply made that way, so you'll have to deal with it, one way or another.
There are also instructions to increase or decrease the value inside the index registers:
You cannot use the above 4 opcodes to manipulate an address. They are solely used for the X and the Y registers.
If you wanted to increase or decrease a value by, say, 95, you wouldn't want to write INC or DEC 95 times. Thankfully, the SNES has instructions for such situations as well.
Just for emphasis: ADC adds a value to the accumulator, not a RAM address. SBC subtracts a value from the accumulator.
With ADC and SBC, you can do add and subtract operations on addresses. Here's an example which adds 4 to the value of an address:
Because ADC modifies A rather than addresses, you must first load the address value into A, then do the addition, then store the result back into the address.
If the carry flag wasn't cleared, the addition would've been $05 instead of $04, depending on the state of the carry flag at that moment. Therefore, it's important to be extra sure about the carry flag and just clear it with a CLC
, before the ADC.
The opposite is also true for subtracting:
This will subtract 4 from the RAM address' content ($0F-#$04
). You'll notice that for subtracting, we set the carry flag rather than clear it. If you didn't set the carry flag, it would subtract $05 instead of $04. This might seem backwards, but it's just how the processor works.
In short: when adding, use CLC
. When subtracting, use SEC
.
When you use ADC, and the value in A wraps from $FF to $00, the carry flag will be set. This is also true for 16-bit A, when the value wraps from $FFFF to $0000.
When you use SBC, and the value in A wraps from $00 to $FF, the carry flag will be cleared. This is also true for 16-bit A, when the value wraps from $0000 to $FFFF.
With this, you can use the carry flag to check if some sort of value wrapping has occured.
The opcodes ADC and SBC are unique in the sense that they're two of the three opcodes which can affect the signed overflow processor flag as a result of a calculation.
The overflow flag is especially relevant when you decide to treat values as signed values. Remember the hexadecimal chapter with the signed and unsigned values? Values $00-$7F
are considered positive, and values $80-$FF
are considered negative.
The overflow flag is set when the result of an operation doesn't make sense in the math world:
Adding a negative value to a negative value, and getting a positive value as a result, when it should be negative
Adding a positive value to a positive value, and getting a negative value as a result, when it should be positive
Subtracting a positive value from a negative value, and getting a positive value as a result, when the negative value should be even more negative
Subtracting a negative value from a positive value, and getting a negative value as a result, when the value should be even more positive
Math rules are at play here. Adding two negative numbers results in a negative number (e.g. -10 + -1 = -11
). Subtracting two negative numbers results in a negative number (e.g. -10 - -1 = -9
). Subtracting a negative value equals an addition (e.g. 10 - -1 = 11
). Adding a negative value equals a subtraction (e.g. 10 + -1 = 9
). The scenarios described in those bullet points break these rules.
Here are some examples of the overflow flag getting set:
All the previous explanations and behaviours apply to 16-bit math as well.
Opcode
Full name
Explanation
INC
Increase
Increases accumulator or memory by 1
DEC
Decrease
Decreases accumulator or memory by 1
Opcode
Full name
Explanation
INX
Increase X
Increases X by 1
DEX
Decrease X
Decreases X by 1
INY
Increase Y
Increases Y by 1
DEY
Decrease Y
Decreases Y by 1
Opcode
Full name
Explanation
ADC
Add with carry
Adds a given value to A
SBC
Subtract with carry
Subtracts a given value from A