Wikia

ROM Hack City

Addition

Talk0
83pages on
this wiki

The typical processor can perform the addition of two numbers. We use the + sign to show addition of the first number to the second number:

first + second

Addition is commutative, which means that first + second is equal to second + first, so the order of the two values is never important.

Addition of two integers might overflow the width of the answer. You can check for unsigned overflow using a carry flag, or for signed overflow using a signed overflow flag.

Contents

Binary addition Edit

This is how to add two binary digits.

first + second => answer

  • 0 + 0 => 00, carry the 0
  • 0 + 1 => 01, carry the 0
  • 1 + 0 => 01, carry the 0
  • 1 + 1 => 10, carry the 1

The answer has two digits. We carry the more significant digit to the next place. This is how to add two bits with a carry.

carry + first + second => answer

  • 0 + 0 + 0 => 00, carry the 0
  • 0 + 0 + 1 => 01, carry the 0
  • 0 + 1 + 0 => 01, carry the 0
  • 0 + 1 + 1 => 10, carry the 1
  • 1 + 0 + 0 => 01, carry the 0
  • 1 + 0 + 1 => 10, carry the 1
  • 1 + 1 + 0 => 10, carry the 1
  • 1 + 1 + 1 => 11, carry the 1

Addition of unsigned integers Edit

To add a pair of unsigned integers, we work from right to left, from the least significant bit to the most significant bit. We add the bits in each place and we carry.

To compute 27 + 13 => 40 like an 8-bit processor, we write 27 as %00011011 and 13 as %00001101, then we add.

 (carry)   00011111
 (first)    00011011      27
(second)  + 00001101    + 13
          ==========    ====
            00101000      40
           0 => carry flag

The last carry bit does not fit in the 8-bit answer, but the processor might put the last carry bit in a carry flag.

Unsigned overflow Edit

When the sum of a pair of unsigned integers is too large to fit in the answer, then the answer overflows.

For example, an 8-bit processor can handle unsigned integers from 0 to 255. If an 8-bit processor computes 211 + 104, then the answer will not be the correct 315.

 (carry)   11000000
 (first)    11010011      211
(second)  + 01101000    + 104
          ==========    =====
            00111011       59
           1 => carry flag

The processor is in this example yielded 59, which is 315 modulo 256.

If the processor put the last carry bit in a carry flag, then we can use the flag to check for unsigned overflow. The carry flag is set to one if we have unsigned overflow, or clear to zero otherwise.

Extended addition Edit

We can use the carry flag to extend the addition to wider integers, if the processor has an "add with carry" instruction.

For example, an 8-bit processor can do 24-bit addition using a chain of three 8-bit additions. We work from right to left, from the least significant byte to the most significant byte. First we add the two least significant bytes. Then we add the two middle bytes with the carry flag. Last we add the two most significant bytes with the carry flag.

We use this way to compute 10730671 + 1673742 => 12404413.

 (carry)   000000111<--101110000<--000001110
 (first)    10100011    10111100    10101111     10730671
(second)  + 00011001  + 10001010  + 00001110    + 1673742
          ==========  ==========  ==========    =========
            10111101    01000110    10111101     12404413
           0 => carry flag

Addition of signed integers Edit

To add a pair of twos-complement signed integers, we use the same procedure as for unsigned integers. Thus we use the same instructions of the processor for signed addition as for unsigned addition.

To compute -45 + 104 => 59 like an 8-bit processor, we write -45 as %11010011 and 104 as %00001101, then we add. The computation is the same as for unsigned 211 + 104.

 (carry)   11000000   unsigned   signed
 (first)    11010011      211      -45
(second)  + 01101000    + 104    + 104
          ==========    =====    =====
            00111011       59       59
           1 => carry flag
          0 => signed overflow flag

Signed overflow is not the same as unsigned overflow. 59 is the wrong unsigned answer but the correct signed answer, so we have unsigned overflow but not signed overflow. The processor might have a signed overflow flag. We use the carry flag to detect unsigned overflow, but we use the signed overflow flag to detect signed overflow.

To compute -6046545 + 1673742 => -4372803 like an 8-bit processor, we use extended addition of 24-bit signed integers. The computation is the same as for unsigned 10730671 + 1673742.

 (carry)   000000111<--101110000<--000001110
 (first)    10100011    10111100    10101111     -6046545
(second)  + 00011001  + 10001010  + 00001110    + 1673742
          ==========  ==========  ==========    =========
            10111101    01000110    10111101     -4372803
           0 => carry flag
          0 => unsigned overflow flag

Signed overflow Edit

There are two ways for addition to cause signed overflow.

  • We add two positive numbers and get a negative number.
  • We add two negative numbers and get a positive number or get zero.

To detect signed overflow, the processor must look at the last two carry bits.

These are the eight possible cases. (Pretend that zero is also "positive".)

 (carry)   00                     (carry)   00
 (first)    0nnn positive         (first)    0nnn positive
(second)  + 0nnn positive        (second)  + 1nnn negative
          ===============                  ===============
            0nnn positive                    1nnn negative
           0 => carry                       0 => carry
          0 => signed overflow             0 => signed overflow

 (carry)   00                     (carry)   10
 (first)    1nnn negative         (first)    1nnn negative
(second)  + 0nnn positive        (second)  + 1nnn negative
          ===============                  ===============
            1nnn negative                    0nnn positive
           0 => carry                       1 => carry
          0 => signed overflow             1 => signed overflow

 (carry)   01                     (carry)   11
 (first)    0nnn positive         (first)    0nnn positive
(second)  + 0nnn positive        (second)  + 1nnn negative
          ===============                  ===============
            1nnn negative                    0nnn positive
           0 => carry                       1 => carry
          1 => signed overflow             0 => signed overflow

 (carry)   11                     (carry)   11
 (first)    1nnn negative          (first)    1nnn negative
(second)  + 0nnn positive         (second)  + 1nnn negative
          ===============                  ===============
            0nnn positive                    1nnn negative
           1 => carry                       1 => carry
          0 => signed overflow             0 => signed overflow

Notice that when the last two carry bits are equal, then signed overflow never happens; but when the last two carry bits are not equal, then signed overflow always happens. This is the rule that processors must follow to set or clear the signed overflow flag.

If you read the documentation for a processor, and the documentation describes a flag that checks the equality of the last two carry bits, then you know that this flag is a signed overflow flag.

Floating-point addition Edit

Many ROM hacks have no floating-point numbers. You might find floating-point numbers in modern computers, and in ROM-hacking tools for modern computers.

Addition of floating-point numbers tends to go well. One of the possible problems is subtractive cancellation, which happens when you add two numbers but the sum is close to zero. Then the sum may have more error than usual.

This is some example from a modern computer.

> -0.000000000005431 + 0.000000000005432
=> 1.0000000000005e-15

> -1.000000000005431 + 1.000000000005432
=> 1.11022302462516e-15

The correct answer for both sums is exactly 1.0e-15. Now 1.0000000000005e-15 is close but 1.11022302462516e-15 is wrong by more than 11%.

Addition by processor Edit

You can help ROM Hack City by adding a section for your processor, or by making the section more complete and accurate.

6502 and 65816 Edit

TODO... Move most everything to the clc and adc pages. Keep here only a brief summary. --Kernigh 15:33, 28 August 2009 (UTC)

The two instructions to learn are

  • clc to clear the accumulator.
  • adc to add the operand and the carry flag to the accumulator.

This is the full list of clc and adc instructions.

	;; 6502 and 65c02 and 65816
	clc
	adc	#$nn		; 8-bit immediate value
	adc	$nn		; direct page
	adc	$nn,x
	adc	$nnnn		; 16-bit address
	adc	$nnnn,x
	adc	$nnnn,y
	adc	($nn,x)		; indirect 16-bit address from direct page
	adc	($nn),y

	;; only 65c02 and 65816
	adc	($nn)		; indirect 16-bit address from direct page

	;; only 65816
	adc	#$nnnn		; 16-bit immediate value
	adc	$nn,s		; stack
	adc	($nn,s),y	; indirect 16-bit address from stack
	adc	$nnnnnn		; 24-bit long address
	adc	$nnnnnn,x
	adc	[$nn]		; indirect 24-bit long address from direct page
	adc	[$nn],y

To compute left + right, you need to load left in the accumulator, clear the carry flag with clc, then add right with adc. The answer will be in the accumulator, but you can sta the answer elsewhere.

	;; left + right => sum
	lda	left		; A = left
	clc
	adc	right		; A += right
	sta	sum		; sum = A

To sum more than two values, you can apply clc and adc in a chain.

	;; term1 + term2 + term3 + term4 => sum
	lda	term1
	clc
	adc	term2
	clc
	adc	term3
	clc
	adc	term4
	sta	sum

One of the 65816 mistakes is to forget clc before adc. You always need clc before adc, unless

  • you are performing extended addition, or otherwise need to add the carry flag.
  • you care not if the sum is off by one.
  • you know that the carry flag is already clear (but if you edit the code, you might need to insert the clc).

If you have adc without clc, then a good idea is to provide a comment that explains why.

	lda	term
	adc	#3		; add a small amount, 3 or 4

One use for extended addition is to add two 16-bit integers. You add the low bytes, then carry, then add the high bytes. The low bytes and high bytes can be anywhere in memory, big-endian, little-endian, or in separate tables. This example uses the little-endian byte order, which is the same order that the 6502 uses for 16-bit addresses. In little-endian byte order, the low byte is at some address, while the high byte is at address + 1.

	;; left + right => sum, using 16-bit extended addition
	lda	left
	clc
	adc	right
	sta	sum
	lda	left + 1
	;; carry
	adc	right + 1
	sta	sum + 1

If you have the 65816, then you can use the 16-bit accumulator, which is easier than coding the extended addition.

	;; left + right => sum, using 16-bit mode of 65816
	rep	#$20		; switch to 16-bit A
	lda	left
	clc
	adc	right
	sta	sum
	sep	#$20		; return to 8-bit A
Advertisement | Your ad here

Photos

Add a Photo
10photos on this wiki
See all photos >

Recent Wiki Activity

See more >

Around Wikia's network

Random Wiki