0

Let's say I have an initial flag condition of z=0, n=0,c=1, q=0,v=0;

and the following registers r1=1000 0003 H r2=1000 0004 H

and have the following instruction: ADCS r1,r2

Would the r1 be 2000 0007 H with the new updated carry set which is zero or 2000 0008 H with the carry from the initial condition?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • 1
    Erm, `2000 0008` with the carry clear. This addition does not produce outgoing carry. PS: you can test this in a debugger yourself. – Jester Feb 12 '23 at 23:25
  • The old C is an input to ADCS, that's why it's useful for propagating carry across 32-bit chunks. (You can think of it as glueing together two 32-bit adders to make a single 64-bit adder, or wider if you repeat ADCS more times. See https://en.wikipedia.org/wiki/Adder_(electronics)#Ripple-carry_adder for how a binary adder is made of multiple full adders.) – Peter Cordes Feb 12 '23 at 23:28
  • 1
    it replaces the carry in of the normal add which is a zero. that is the only way an add with carry can be useful. try it with pencil and paper. – old_timer Feb 13 '23 at 16:21

2 Answers2

1

The old value of the carry flag is included in the addition, and it is set afterwards to indicate whether the new addition caused a carry. Following your example code, r1 will equal 20000008H and the carry flag will be zero.

The main point of an add-carry instruction is to be used in a loop to add multiple-precision integers one word at a time, propagating the carry through. So it can't really work any other way than this.

In general, for such questions, if a test is not enough to convince you, then refer to the ARM Architecture Reference Manual. They have detailed pseudocode for every instruction that defines precisely what it does. For this instruction they have

(result, nzcv) = AddWithCarry(R[n], shifted, PSTATE.C);
// ... irrelevant other stuff
PSTATE.<N,Z,C,V> = nzcv;

showing clearly that the value of the carry flag is used before being updated.

Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82
1

Think about the purpose of an add with carry. It is to cascade addition

So if the logic has 32 bit registers I can add 64, 96, etc all the way up to however much storage I have and care to use

A simple add

     0
  0011
+ 0111
=======

fill it in

 01110
  0011
+ 0111
=======
  1010

So the result is 1010 with a carry out of 0

Now that could be visualized with an add and and adc

   x 110
  00  11
+ 01  11
====  ===
      10

x is normally 0 for an ADD. But for ADC the carry out flag which comes from the carry out of a prior operation is used as the carry in.

 011 110
  00  11
+ 01  11
====  ===
  10  10

The add on the right 10 with a carry out of 1, and the left uses that carry in.

The result is still 1010 with a carry out of 0.

This scales up to whatever number of bits in your registers or alu.

ADC means the carry flag is used as the carry in for the addition.

Subtract with borrow is slightly more complicated as some architectures invert the carry out and you need to invert the carry in, but still you can do the same math as above and see subtract with borrow uses the carry flag just like add with carry.

So

z=0, n=0,c=1, q=0,v=0;
1000 0003 H r2=1000 0004

                                  1
   00010000000000000000000000000011
+  00010000000000000000000000000100
======================================

and you can easily fill that in.

old_timer
  • 69,149
  • 8
  • 89
  • 168