해결된 질문
작성
·
507
1
강사님. 안녕하세요. 강의 잘 보고 있습니다.
파이프라인에 대해 갑자기 궁금증이 생겼는데요.
1. thumb/thumb2와 관계없이 프로그램 카운터의 위치는 항상 PC = 현재 명령어 위치 + 4라 설명하신 것 같은데요. thumb의 경우 2바이트 명령어니 이해가 갑니다만 thumb2는 4바이트라 PC = 현재 명령어 위치 + 8이 되는게 아닌가요? 왜 항상 PC = 현재 명령어 위치 + 4 인지 궁금합니다.
명령어를 페치하는 기본 단위는 32비트라 되어있습니다.
2. 명령어 페치시 만약 thumb 코드라면 2개의 명령어를 페치한다는 것 같은데, 만약 A 명령어와 B 명령어(둘 다 thumb)를 페치한다면 이 두 명령어의 파이프라인 동작이 어떻게 되나요?
A 명령어 먼저 F-D-E되고 그 후에 B 명령어가 F-D-E가 파이프라인으로 동작하게 되는건가요?
3. 그렇다면 만약 thumb명령어와 thumb2명령어가 페치될 경우에 어떻게되나요?
A 명령어(thumb라 가정), B 명령어(thumb2라 가정)일 때, 32비트 페치시 A 명령어와 B1(B 명령어의 2바이트)가 페치될 것으로 예상이 됩니다만, 그 후의 동작이 이해가 되지 않습니다.
항상 질문에 친절하게 답변해주셔서 감사합니다.
답변 2
0
0
안녕하세요. 김상현님!
질문하신 여러가지에 공통적으로 적용될 3가지 기본 전제가 있습니다.
첫째, thumb-2 인스트럭션 세트의 주요 목표는 코드 밀도를 높이고 메모리 사용을 줄이기 위함임
둘째, AMBA 시스템 버스가 32비트 버스로 운용된다는 사실. 메모리는 32비트로 R/W 하였을 때 최적
셋째, PC 는 프로그램을 실행하는 데 관여하는 것이 아닌, 코드 페치에 사용된다
메모리 평균 접근 속도를 높이기 위해선 페치(FETCH) 는 32비트로 운용하는것이 효율적일 것입니다. 이는 이후 16비트 명령어는 2개 분량, 32비트 명령어로는 1개 분량에 대한 것을 이해하는 데 기초가 됩니다.
그렇다면, 아래와 같이 명령어들이 나열되어 있을 때는 어떻게 처리될까요?
(1)번을 처리하고 난 후, (2)(3)번을 한번에 페치하여 처리할 것을 짐작할 수 있겠죠. 그렇기에 (2)번 라인을 실행할 때는 페치를 건너뛸 것(쉬고 간다는 뜻)을 예상할 수 있을 겁니다.
(1)thumb2 명령어(32비트 명령어)
(2)thumb 명령어(16비트 명령어)
(3)thumb 명령어(16비트 명령어)
(4)thumb2 명령어(32비트 명령어)
그래서, 실제로 그렇게 되는지 제가 실험을 해보았습니다.
이번 실험에 사용된 코드입니다.
/*
void THUMB2_TEST(void)
------------------------
*/
.global THUMB2_TEST
THUMB2_TEST:
mov r3,pc @T1
ldr.w r2,[pc] @T2
mov r3,pc @T3 PC=080001fa 로 확인
mov r3,pc @T4 PC=0x80001fc 로 확인
ldr.w r2,[pc] @T5
mov r3,pc @T6
ldr.w r2,[pc] @T7
mov r3,pc @T8
디버거로 테스트한 결과입니다
브레이크 포인트를 24번 라인에 걸어놓고 실행해보면 23번 라인의 코드가 실행되었을 당시의 PC 값을 알 수 있겠죠?. 화면에 보시는 것처럼 PC=080001fa 이렇게 나옵니다.
그리고, 기존 브레이크 포인트를 지우고 새 브레이크 포인트를 25번 라인에 걸어놓고 실행해보면 24번 라인의 코드가 실행되었을 당시의 PC 값은 PC=080001fc 이렇게 나옵니다.
이로써 알 수 있는 것은 PC 는 THUMB/THUMB2 와 관계없이 PC + 4 단위로 증가(alignment 4 유지)한다는 사실입니다. 글 서두의 가정을 만족하는 결과입니다.
이 실험을 통해 추가적인 정보도 확인할 수 있었는데요.
R2 에 파란색 테두리로 표시한 부분(0x467b2000)이 로드되었다는 사실입니다.
왜 이런식으로 처리가 되는 지에 대해서는 강의(s335_LDR 명령어의 주소 해석법) 에서 다루었죠.
(참조)
궁금하신 부분에 대하여는 official ARM TRM 에서도 명확하게 설명하고 있는 것을 찾기 어려웠고, 때문에 이 부분에 대한 제 설명이 확실히 맞다고 제시할 만한 어떤 근거는 없습니다.
legacy ARM7, 9 시절의 파이프라인 동작 원리를 THUMB-2 기반 cortex-m 에 대입하면 이해하기 어려운 지점이 생깁니다. 이와 관련하여 잘 정리된 문서를 찾기도 어렵고요.
다만, 저도 이번 질문을 계기로 더 자세히 들여다 보게 되었습니다.
제가 위 답 글의 마지막에 드린 링크를 안들어가 보셨다면, 한번 보시길 추천드립니다.
그곳에 힌트가 될 만한 내용이 아래와 같이(적색부) 적혀있습니다. 출처를 밝히기 어렵지만 제가 어디서 본 글에 따르면 thumb-2 명령어는 단순한 32비트 명령어로 생각하면 안되고 16비트 명령어 2개를 접착? 해놓은 것으로 바라봐야 한다는 것입니다. 그렇다면 아래 글이 그 말의 논거를 뒷받침해주는 글로 볼 수 있을 겁니다.
아무래도 말씀하신 PC+8 이런식으로 처리되는 것은 아닌 것 같네요. 다시한번 말씀드리지만 페치는 thumb, thumb-2 공히 모두 +4, 실행은 하프워드 단위로 처리하는 것으로 판단됩니다.
하프워드를 읽어보니(디코딩) thumb 명령어로 확인되면 바로 실행하게 되고, 32비트 thumb-2 로 확인되면 나머지 하프워드를 추가적으로 읽어서(디코딩) 실행하게 되는 것이죠.
▲출처: 스택오버플로우
이 때문에 다음과 같은 실험을 추가적으로 해 보았습니다.
놀랍게도? 25 라인의 명령 실행을 통해 r0 로 읽힌 값은 자기 자신의 opcode(0xF8DF0000) 인 것을 확인할 수 있었습니다. PC+8 로 처리된다면 절대로 있을 수 없는 일입니다.
딱 하나가 이해가 안됩니다.
페치 기본 단위가 32비트라는 것을 알겠습니다.
그런데 PC 는 프로그램을 실행하는 데 관여하는 것이 아닌, 코드 페치에 사용된다면
PC + 4 단위로 증가가 되는지 이해가 되지 않습니다.
Cortex-M3는 3단계 파이프라인으로 Fetch - Decode - Execute인데
Decode 단계와 Execute 단계에서 Thumb 코드만 사용되었다면 PC + 4가 맞다고 이해가 가는데
지금보면 Thumb/Thumb2에 관계없이 PC+4라 되어있는데...
만약 Thumb2 코드만 사용되었다면 PC는 PC+8이 되어야하는 것 아닌가요?
이게 굉장히 이해가 안됩니다...