Assembly uses integers as variables. An integer is a whole number, like 0, 1, 2, et cetera. In Assembly, we can use signed and unsigned integers. This post will explain briefly what they are, and what the difference is.
Note: if you’re unfamiliar with the binary number system, I’d suggest you read up on bits, bytes and number systems first.
The NES is an 8-bit system, which means a single variable can hold eight bits (or one byte) of data. This variable is a number from 0 (#%00000000) to 255 (#%11111111). These positive integers are called unsigned integers.
Sometimes though, you might need a negative number in your code. For example, let’s take a look at vertical speed in a platformer game. When the player jumps, it moves up, giving it a “negative speed” as the y-position on the screen gets smaller. When gravity hits, the player falls back to the ground, giving it a positive speed where the y-position on the screen gets bigger. How can we define a negative value if the variable is always between 0 and 255?
Signed integers
This is when we use a signed integer. With a signed integer, the leftmost bit of the value indicates whether the number is negative or positive. This means we can now assign a negative value to a variable: #%0xxxxxxx are positive integers, and #%1xxxxxxx are negative integers. When you subtract one from #%00000000 (which is zero in decimal), the value will change to #%11111111, which equals -1 in decimal. Here’s a table with a few binary, signed and unsigned integer values.
Binary | Unsigned integer | Signed integer |
---|---|---|
#%00000000 | 0 | 0 |
#%00000001 | 1 | 1 |
#%00000010 | 2 | 2 |
#%00000011 | 3 | 3 |
… | ||
#%01111110 | 126 | 126 |
#%01111111 | 127 | 127 |
#%10000000 | 128 | -128 |
#%10000001 | 129 | -127 |
#%10000010 | 130 | -126 |
… | ||
#%11111110 | 254 | -2 |
#%11111111 | 255 | -1 |
So, how do we tell the game whether an integer is signed or unsigned? Well, actually we don’t! Because bytes are just that: bytes, sets of eight bits. The game does not know by looking at a byte if it’s a signed or unsigned integer. The math even works the same! Try adding together two binary values: the result will be correct, whether you interpret them as signed or unsigned. Also, whether you add 130 to an 8-bit binary, or subtract 126, the resulting byte will be the same. The main difference is that an unsigned integers overflows between #%00000000 and #%11111111, and a signed integer overflows between #%01111111 and #%10000000. This is why for example signed integers need different branch instructions than unsigned integers (BPL and BMI, instead of BCS and BCC).