질문
cmp 명령은 sub 명령과 거의 흡사하고 차이점이라면 cmp는 목적지 피연산자를 수정하지 않는다는 점이라고 알고 있고 뺄셈연산은 피연산자를 2의 보수로 취하여 덧셈하는것과 같다고 알고 있었다는 전제하에 아래의 경우는 모두 같은 결과를 내놓을줄 알았는데 문제는 Carry flag 가 CMP 그리고 SUB 와 ADD가 서로 다른 결과를 보이는 이유는 무었일까요?
첫번째, cmp 명령의 결과 Carry flag 는 0, AL=4
두번째, sub 명령의 결과 cmp와 동일하게 Carry flag 는 0, AL=3
세번째, add 명령의 결과 cmp, sub 와는 반대의 결과인 Carry flag는 1, AL=3
답변(해설)
SUB의 경우는 다음과 같이 계산되어 최상위 비트(MSB)에서는 자리내림이 발생하지 않아 Carry flag 는 0인 상태를 유지합니다.
0000 0100
- 0000 0001
-------------
0 0000 0011
하지만 ADD의 경우 다음과 같이 계산되어 최상위 비트(MSB)에서 자리올림이 발생하고 Carry flag가 1이 됩니다.
0000 0100
+ 1111 1111 (1의 2의 보수)
-------------
1 0000 0011
근데 이유는 간단합니다.
회로를 설계할때 보통 가산회로는 있으나 감산회로는 가산회로를 이용하여 설계를 하게 됩니다. (모든 회로가 그런것은 아니지만...)
그래서 SUB는 다음과 같이 구현하여 비교해 보아도 동일한 결과값을 출력하게 됩니다.
- 소스 피연산자를 2의 보수로 취한다.
- 목적지 피연산자와 소스 피연산자를 덧셈한다.
결과값으로는 동일한 결과를 수행하기는 했습니다. 하지만 Carry flag 는 두 결과가 반대의 결과를 보이게 됩니다.
이것을 보정하기 위해서 덧셈연산방법에는 다음과 같은 구현조건을 회로에 추가하여 뺄셈시의 Carry flag 와 같도록 추가하였습니다.
이 조건구현으로 감산회로를 가산회로의 조합으로 구현할수 있게 되었답니다.
즉, SUB는 다음과 같은 구현과 동일합니다. (SUB를 ADD연산으로 대체하여 표현할경우 Carry의 특성)
MOV AL, 4 /* 목적지 피연산자 */
MOV CL, 1 /* 소스 피연산자 */
NEG CL /* 2의 보수 */
ADD AL, CL /* 덧셈 */
CMC /* Carry flag 반전 */