Discussion:
CMP and SUB instructions of ARM CPU.
(too old to reply)
HiSt
2009-05-16 02:47:38 UTC
Permalink
Hello!


Somewhere in the specifications of ARM CPUs
it states that CMP is like a SUB instruction
without register overwrite...

mov r0,0
mov r1,1
cmp r0,r1

As "cmp r0,r1" is equivalent to
"sub r0,r0,r1" (without writing r0)
and equivalent to "r0-r1"
then the Carry flag (C) should be set in this example,
but IT IS NOT, at least for the CMP instruction.

This means that the CS (Carry Set) and CC (Carry Clear)
condition codes must be interpreted inverted:
CC == "r0 unsigned lower than r1", (normally r0 > r1)
CS == "r0 unsigned higher or same than r1", (normally r0 <= r1)

This leads to weird condition codes for
comparing and branching, for people that
have been programming i86 and 68000.

Is this a specification fault of ARM?


Greetings!
H.Samso (thebitsclub.tripod.com)
Ben Avison
2009-05-16 12:17:29 UTC
Permalink
Post by HiSt
mov r0,0
mov r1,1
cmp r0,r1
As "cmp r0,r1" is equivalent to
"sub r0,r0,r1" (without writing r0)
and equivalent to "r0-r1"
then the Carry flag (C) should be set in this example,
but IT IS NOT, at least for the CMP instruction.
[...]
Post by HiSt
This leads to weird condition codes for
comparing and branching, for people that
have been programming i86 and 68000.
Is this a specification fault of ARM?
It's not wrong, it's just different. ARM uses C as a NOT-borrow flag for
subtraction operations. Yes, it's different from some architectures, but
it's the same as others, notably the 6502 (which was the previous
architecture used by ARM's original designer, Acorn Computers).

This behaviour is also entirely consistent with ARM's RISC philosophy: when
the C flag is defined in this way, the only difference between ADC and SBC
is that the second source register is NOTted for SBC.

Ben
HiSt
2009-05-16 16:08:58 UTC
Permalink
Post by Ben Avison
  mov  r0,0
  mov  r1,1
  cmp  r0,r1
As "cmp r0,r1" is equivalent to
"sub r0,r0,r1" (without writing r0)
and equivalent to "r0-r1"
then the Carry flag (C) should be set in this example,
but IT IS NOT, at least for the CMP instruction.
[...]
This leads to weird condition codes for
comparing and branching, for people that
have been programming i86 and 68000.
Is this a specification fault of ARM?
It's not wrong, it's just different. ARM uses C as a NOT-borrow flag for
subtraction operations. Yes, it's different from some architectures, but
it's the same as others, notably the 6502 (which was the previous
architecture used by ARM's original designer, Acorn Computers).
This behaviour is also entirely consistent with ARM's RISC philosophy: when
the C flag is defined in this way, the only difference between ADC and SBC
is that the second source register is NOTted for SBC.
Ben
Then the specification would better state (in the next revision)
that it offers a Borrow (B) flag when using SUB, and that it is
a Carry (C) flag when using ADD. For unsigned, at least.

Because, when using ADD with the 2complement of the substractor,
and substractor is higher, the Carry is not set (Borrow). But if the
substractor is lower, and adding its 2complement, the carry is set
(Borrow).

Borrow is the inverted Carry:
r0 < r1: r0 + complement2(r1) -> Carry Clear
r0 > r1: r0 + complement2(r1) -> Carry Set

You mean that when using SUB it negates the Carry,
very advanced. :)
Maybe it uses a complement2() and Add() the ARM processor, when
instructing a SUB.

Greetings,
H.Samso (thebitsclub.tripod.com)
Wilco Dijkstra
2009-05-16 18:02:24 UTC
Permalink
Post by HiSt
Post by Ben Avison
mov r0,0
mov r1,1
cmp r0,r1
As "cmp r0,r1" is equivalent to
"sub r0,r0,r1" (without writing r0)
and equivalent to "r0-r1"
then the Carry flag (C) should be set in this example,
but IT IS NOT, at least for the CMP instruction.
[...]
This leads to weird condition codes for
comparing and branching, for people that
have been programming i86 and 68000.
Is this a specification fault of ARM?
It's not wrong, it's just different. ARM uses C as a NOT-borrow flag for
subtraction operations. Yes, it's different from some architectures, but
it's the same as others, notably the 6502 (which was the previous
architecture used by ARM's original designer, Acorn Computers).
This behaviour is also entirely consistent with ARM's RISC philosophy: when
the C flag is defined in this way, the only difference between ADC and SBC
is that the second source register is NOTted for SBC.
Then the specification would better state (in the next revision)
that it offers a Borrow (B) flag when using SUB, and that it is
a Carry (C) flag when using ADD. For unsigned, at least.
Because, when using ADD with the 2complement of the substractor,
and substractor is higher, the Carry is not set (Borrow). But if the
substractor is lower, and adding its 2complement, the carry is set
(Borrow).
Basically the Carry flag is just the carry-out of the 32-bit adder (ie. bit 32).
There is no borrow flag or anything similar. The ARM-ARM explicitly states
that subtract is done by inverting the input and forcing the carry input flag to 1.
You're right that the meaning of that carry flag depends on the operation you've
done, after an add it gives you unsigned overflow, after subtract it tells you
which operand is larger. If you use CC/CS for add, and LO/HI/LS/HS for sub
then you can avoid having to think about the details...
Post by HiSt
r0 < r1: r0 + complement2(r1) -> Carry Clear
r0 > r1: r0 + complement2(r1) -> Carry Set
You mean that when using SUB it negates the Carry,
very advanced. :)
Maybe it uses a complement2() and Add() the ARM processor, when
instructing a SUB.
All ALUs use ones-complement and set the carry-in to implement subtract.
This is almost the same as your complement2() except when both operands
are zero (0 + 0 gives carry clear, 0 - 0 gives carry set).

Wilco

Loading...