ADD, ADC, SUB, SBC and RSB
이번에는 가장 간단한 레지스터 연산인 ADD, ADC, SUB, SBC, RSB 에 대해 알아보겠습니다.
ADD : Add
레지스터 끼리의 값을 더하거나, 레지스터의 값과 상수값을 더합니다.
실행 전 :
"ADD R1,SP,#0x8" 명령을 통해
스택포인터(R13)의 값에 0x8을 더해 R1에 입력합니다.
실행 후 :
R1값이 R13의 값(0x2000_2430)보다 0x8만큼 큰 0x2000_2438로 변했습니다.
ADC : Add with carry
레지스터 끼리 값을 더할 때, Carry비트의 값을 추가해 줍니다.
Carry비트의 SET/CLEAR 여부에 따라 결과가 달라집니다.
Carry 비트가 "0"인 경우
실행 전 :
"ADC R2,R1,R0" 명령의 수행결과는, R2=R1+R0+Carry 와 같습니다.
아래의 그림에서 C(Carry)비트는 0으로 클리어 되어 있음을 확인할 수 있습니다.
실행 후 :
"ADC R2,R1,R0" 수행 결과, "R2 = 1(R1) + 0(R0) + 0(Carry)" 이 되어,
R2의 값이 1로 변경되었음을 확인할 수 있습니다.
Carry 비트가 "1"인 경우
실행 전 :
"ADC R4,R3,R0" 명령의 수행결과는, R4=R3+R0+Carry 와 같습니다.
아래의 그림에서 C(Carry)비트는 1로 세트 되어 있음을 확인할 수 있습니다.
실행 후 :
"ADC R4,R3,R0" 수행 결과, "R4 = 1(R3) + 0(R0) + 1(Carry)" 이 되어,
R4의 값이 2로 변경되었음을 확인할 수 있습니다.
SUB : Subtract
레지스터 끼리의 값을 빼거나, 레지스터의 값에서 상수값을 뺍니다.
실행 전 :
"SUB SP,SP,#0x1C" 명령을 통해
스택포인터(R13) 의 값을 0x1C만큼 감소시킵니다.
실행 후 :
수행 결과, R13의 값이 0x2000_244C에서 0x2000_2430으로 0x1C만큼 감소하였습니다.
SBC : Subtract with carry
ADD, SUB, ADC, SBC 등의 명령어 중에서 가장 혼동되기 쉬운 어셈블리가 아닐까 생각됩니다.
레지스터 끼리의 값을 빼되, Carry비트가 클리어(0)되어 있으면, 값을 추가로 1만큼 감소시킵니다.
자세한 것은 아래의 예를 통해서 살펴보도록 하겠습니다.
Carry 비트가 "0"인 경우
실행 전 :
아래의 "SBC R2,R1,R0" 명령의 경우,
R2=R1-R0-1(Carry가 0이므로) 의 결과를 갖게 됩니다.
실행 후 :
결과적으로 R2값이 1(R1)-0(R0)-1(Carry가 0이므로) 이 되어 "0"값을 갖게 됩니다.
Carry 비트가 "1"인 경우
실행 전 :
아래의 "SBC R4,R3,R0" 명령의 경우,
R4=R3-R0-0(Carry가 1이므로) 의 결과를 갖게 됩니다.
실행 후 :
결과적으로 R4값이 1(R3)-0(R0)-0(Carry가 1이므로) 이 되어 "1"값을 갖게 됩니다.
RSB : Reverse subtract
서로 값을 빼는 것은 "SUB(Subtract)"와 동일하나, SUB 명령과 반대(Reverse) 방향으로 빼줍니다(Subtract).
(예 : SUB R1,R0,#0x700 --> R1=R0-0x700
RSB R1,R0,#0x700 --> R1=0x700-R0)
실행 전 :
아래의 "RSBS R1,R1,#0x700" 명령을 통해,
0x700에서 R1을 뺀 후, 그 값을 R1으로 입력합니다.
실행 후 :
"RSBS R1,R1,#0x700" 수행결과,
R1의 값이 0x600에서 0x100으로 변경되었습니다. (R1 = 0x700-0x600 = 0x100)
추가로 살펴볼 것은,
앞의 예제들이 모두 ADD, ADC, SUB, SBC 로 "S" suffix가 없었던데 반해,
이번 예제는 "RSBS R1,R1,#0x700" 으로 "RSB" 명령 뒤에 "S" suffix가 붙어 있는 것을 볼 수 있습니다.
이렇게 ADD/SUB 등에 "S" suffix가 붙어 있는 경우 연산결과에 따라,
N(Negative), Z(Zero), C(Carry), V(oVerflow) 등의 condition flag가 설정될 수 있습니다.
위의 스크린샷에서도 이전까지는 클리어 상태이던 "C"비트가 연산 결과 후 세트 되는 것을 볼 수 있습니다.
The Condition flags
Cortex-M은 xPSR(Program Status Register) 를 통해 현재의 프로그램 수행 상태를 나타냅니다.
ADDS, SUBS 등 어셈블리 뒤에 "S" suffix가 붙어 있는 경우, 그 결과에 따라 N, Z, C, V 등의 상태플래그(condition flags) 세트(1)/클리어(0) 됩니다.
xPSR의 비트와 상태플래그의 세트/클리어에 대해서는 아래를 참조하시기 바랍니다.
< ARM의 "DDI0403D_arm_architecture_v7m_reference_manual.pdf" 에서 발췌 >
N(Negative) : 연산의 결과가 음수이면 "1"로 세팅되고, 아니면 "0"으로 클리어 됩니다.
Z(Zero) : 연산의 결과가 "0"이면 "1"로 세팅되고, 아니면 "0"으로 클리어 됩니다.
C(Carry) : 더한 결과가 2^32보다 크거나 같으면 "1"로 세팅되고, 아니면 "0"으로 클리어 됩니다.
뺀 결과가 음수가 아니면 "1"로 세팅되고, 음수이면 "0"으로 클리어 됩니다.
V(oVerflow) : 더하기, 빼기 혹은 비교의 결과가 2^31 이상이거나, -2^31 보다 작으면 "1"로 세팅됩니다.
이상으로 기본적인 레지스터 연산인 ADD, SDC, SUB, SBC, RSB에 대해 알아보았습니다.
잘못된 점이나, 추가 문의사항은 TRACE32@hancommds.com 으로 연락 부탁드립니다.
"TRACE32로 바라본 ARM - Cortex-M" 으로 돌아가기