본문 바로가기
IT/임베디드 시스템

임베디드 시스템 소프트웨어 - 인터럽트 / 마이크로프로세서

by 뽀짝뉴스 2020. 6. 2.

 

이 카테고리 초입에서는 임베디드 시스템에서 사용하는 하드웨어는 건너뛰고, 본론이라고 할 수 있는 임베디드 시스템 소프트웨어로 들어갈 것입니다. 

 

시스템이 뭔가 다른 일을 하고 있는 동안 외부 이벤트에 대해서 빠르게 반응하도록 하는 일은 매우 어려운 일입니다. 가령 우유 저장 창고를 감시하는 시스템이 n번 창고의 양을 계산하고 있는 동안에 n-1 창고의 양을 묻는 동작을 요구하면 시스템은 바로 응답을 해야 하기 때문이죠.

 

시스템의 응답 문제에 접근하는 1번째 방법은 우리가 함께 논의할 인터럽트를 사용하는 것입니다. 인터럽트는 임베디드 시스템 안의 마이크로프로세서가 어떤 일을 하던지 우선 정지시킨 후 인터럽트를 발생시킨 이벤트에 대한 응답으로 다른 코드를 실행시킵니다. 인터럽트는 시스템의 응답 문제를 해결할 수 있지만, 조금 어려운 프로그래밍을 해야 하고, 인터럽트 자신이 시스템에 새로운 문제를 일으킬 수 있다는 점을 고려해야 합니다.

(인터럽트가 발생되었을 때, 처리하는 코드를 일반적으로 인터럽트 루틴이라고 부릅니다. 다시 원래 세팅으로 돌아오는 일은 간단해 보이지만 그렇지 않습니다. 생각처럼 된다면 이렇게 공부할 필요도 없겠지요. 루틴을 수행하면서 원하지 않는 값들이 변경되어 다시 진입이 안 되어 불안정해지는 경우가 특히 많이 발생되곤 합니다.)

 

깊이 들어가기 전에, 먼저 마이크로프로세서가 어떻게 동작하는지 알아야 합니다. 마이크로프로세서 종류에 상관없이 어셈블리 언어에 상당히 익숙해져 있다면, 다음 글로 넘어가도 됩니다. 추후에 다룰 내용을 이해하기에 필요한 마이크로프로세서와 어셈블리 언어에 대해 다룰 것이므로 참고해주세요. 대부분의 마이크로프로세서와 어셈블리 언어는 다른 종류들과 일반적인 부분은 상당히 비슷합니다. 마이크로프로세서와 어셈블리 언어를 복잡하게 하고, 각각의 종류들을 구분 짓게 하는 세세한 사항까지는 다룰 필요가 없기 때문에 공통된 부분만을 다룰 것이라는 것도 알려드립니다.

(만약에 한 가지 종류의 마이크로프로세서와 언어에 익숙해진다면, 다른 어셈블리어는 쉽게 배울 수 있다는 게 정설입니다.)

 

 

[마이크로프로세서에 대해서]

 

어쨌든 익숙하지 않다면 알아야 할 내용에 대해서 얘기해보겠습니다.

  • 어셈블리 언어는 마이크로프로세서가 실제로 실행시키는 기계어 코드에 대한 사람이 읽을 수 있는 형태의 언어라는 것. 어셈블러라 불리는 프로그램은 어셈블리 언어를 마이크로프로세서가 실행하기 전에 영과 일로 되어있는 기계어로 바꿈. 각각의 어셈블리 언어의 명령어는 마이크로프로세서의 기계어 명령어 하나로 변환됨.
  • C 컴파일러가 씨 언어를 컴파일할 때는 대부분의 씨언어 구문이 여러 개의 마이크로프로세서의 기계어로 변환됨. 대부분의 C 컴파일러는 C 소스와 대응되는 어셈블리 언어로 된 리스트 파일을 생성함.
  • 각각의 마이크로프로세서 패밀리는 다른 종류의 기계어를 이해할 수 있기 때문에, 서로 다른 어셈블리 언어를 가지고 있음. 각 묶음 안에서 개개의 마이크로프로세서에 대해 어셈블리 언어는 일반적으로 거의 같음

 

일반적인 마이크로프로세서는 내부에 프로세서 동작에 필요한 변수를 저장할 수 있는 범용 레지스터라 불리는 레지스터 군을 가지고 있습니다. 예를 들어보자면 대부분의 마이크로프로세서는 산술 연산 같은 명령을 수행하기 위해서 계산할 값을 범용 레지스터에 미리 저장시켜야 합니다. 마이크로프로세서 군단은 각각 다른 숫자의 레지스터들을 가지고 있는데 레지스터들에 서로 다른 규칙을 적용하여 이름을 할당합니다. 이 논의를 위해서 언급할 마이크로프로세서에는 M1, M2, M3로 불리는 레지스터를 갖는다고 약속하죠.

 

대부분의 마이크로프로세서는 범용 레지스터 외에 약간의 특수 레지스터를 가지고 있습니다. 대부분 다음 실행할 명령어의 주소를 관리하는 프로그램 카운터를 가지고 있고요. 게다가 일반적인 목적으로 사용하는 스택의 최상위 주소를 가리키는 스택 포인터를 가지고 있습니다.

 

일반적인 어셈블리 언어에서 코드에 변수 이름이 나와있다면 그건 그 변수의 주소를 참조하고 있는 겁니다. 주소가 아닌 변수의 값을 참조하려면 변수 이름을 괄호로 감싸야합니다. 반대로 C 언어 등의 고급 언어에서는 변수 이름을 그냥 쓸 경우 변수 값을 참조하게 됩니다. 다수의 어셈블리어에서 세미콜론 뒤에 오는 것은 모두 주석으로 처리되는 탓에 어셈블러는 번역할 시 세미콜론 뒤부터 해당 라인 끝까지 무시한다고 봐야 합니다.

 

가장 많이 쓰이는 명령어 중의 하나는 데이터를 한 곳에서 다른 곳으로 이동시키는 명령어입니다. 통계적으로 살펴보면 일반적으로 어셈블리 언어로 된 코드의 7할 정도가 이동 명령어라는 말이 됩니다. MOVE M3, M2 이 명령어는 레지스터 M2에서 데이터를 읽어서 M3으로 값을 복사합니다. 같은 문맥에서 다음을 볼까요. MOVE M5, (AA) 이건 메모리로부터 AA의 값을 읽어 레지스터 M5에 값을 저장합니다.

 

다수의 어셈블리 언어는 PUSH와 POP이라는 명령어를 이용해서 스택에 접근합니다. 푸시는 스택 포인터를 변경시키고 데이터를 스택에 추가시킵니다. POP 명령어는 데이터를 읽고 스택 포인터를 되돌리고요. 마지막으로 대부분의 언어는 서브루틴이나 함수로 분기해 실행하는 콜 명령어를 가지고 있고, 다시 돌아오기 위해서 리턴을 씁니다. 일반적으로 마이크로프로세서는 CALL 다음에 수행할 명령어의 주소를 스택에 저장해 놓습니다.

 

 

 

글 발행 후 인터럽트에 대한 내용은 아래 목차를 통해 관련 내용을 볼 수 있도록 링크를 달 것이니 원하는 내용을 찾아보는데 도움이 됐으면 좋겠습니다.

댓글