본 기고에서는 일반적인 소프트웨어 디버깅 수행의 세부적인 내용들과 최첨단 하드웨어 에뮬레이션 시스템의 사용에 따른 이점들을 살펴보고자 한다.
글/Lauro Rizzatti, 검증 컨설턴트
오늘날의 시스템온칩(SoC) 중에 90% 이상이 임베디드 프로세서를 하나 이상 내장하고 있으며, 이들은 실리콘이 제공되기에 앞서 최종 설계 단계를 고려하여 테스트 되어야만 한다. 임베디드 소프트웨어를 어느 정도 포함시키지 않고서는 SoC의 기능성을 완전히 인증할 수 없는데, 일은 여기서부터 복잡해지기 시작한다. 미국 컴퓨터 학회(ACM)에 따르면, 일반적으로 새로운 소프트웨어의 소스 코드 8~12행당 하나 꼴로 오류가 있다고 한다. 디버깅이 완료된 후의 오류율은 소스 100행당 버그 1~5개 수준으로 떨어진다. 검증에 사용되는 소프트웨어가 의미를 가지려면 소스 규모가 수천 행은 되어야만 한다는 점을 염두에 둔다면 임베디드 소프트웨어의 버그는 100 개 정도에 달하게 된다.
문제는 이처럼 명백하지만 그 해결책은 그렇지가 못하다. 하드웨어 에뮬레이션을 통한 소프트웨어 디버깅이 오늘날 필수사항이 된 것은 툴이 엄청난 프로세싱 능력을 갖추게 되었기 때문이다. 유감스럽게도 이것은 저렴한 해결책은 못 된다. 소프트웨어 개발 팀의 수가 하드웨어 설계 팀보다 훨씬 많다는 점을 고려하면 툴에 대한 투자 비용이 천정부지로 솟구칠 것임을 쉽게 알 수 있다.
이러한 난제를 돌파할 방법은 있는 걸까? 대답은‘그렇다’이다. 오프라인 상태에서 이루어지는 실제 소프트웨어 디버깅 단계를를 온라인 에뮬레이션 세션 이후 설계단계로 옮기는 것이다. 사실, 이 방법은 하드웨어 디버깅에 이미 사용되었던 패턴, 즉 에뮬레이션에서 파형을 포착한 뒤 이를 나중에 오프라인 상태에서 디버깅하는 패턴을 그대로 따르고 있다.
본 기고에서는 일반적인 소프트웨어 디버깅 수행의 세부적인 내용들과 최첨단 하드웨어 에뮬레이션 시스템의 사용에 따른 이점들을 살펴보고자 한다.가장 보편적인 소프트웨어 디버깅 수행 기법은 JTAG 프로브를 통하는 것으로서, 이것은 검증 하고자 하는 디자인(DUT)에 물리적으로나 가상으로 연결할 수 있다. 그대안은 트레이스 기반의 방법들을 사용하는 것으로서, 이경우에는 DUT로부터 정보를 수집한 뒤에 이를 개발자들에게 제공함으로써 소프트웨어의 동작을 이해할 수 있도록 돕는 것이다
물리적 JTAG
가장 기본적인 수준의 디버깅은 물리적인 JTAG 프로브를 에뮬레이터 내부에 매핑된 DUT에 부착함으로써 달성할 수 있다. DUT로부터 나오는 JTAG 신호들은 에뮬레이터에 설치된 I/O 카드로 트레이스 되며, JTAG 물리적 프로브는 이 I/O에 연결되어 있다. 이 프로브는 하나 또는 다수의 프로세서 상에서 실행되는 소프트웨어를 제어 및 검사하는 디버거에 인터페이스 되어 있다.
이 접근 방법의 주된 이점은 대부분의 개발자들이 이방법을 이미 잘 이해한다는 점인데, 이것이 개발 보드에서 프로브를 실행시키는 것과 거의 같은 방식이기 때문이다. 추가적인 이점은 이 프로브가 사용하는 JTAG 프로토콜이 에뮬레이터의 상대적으로 느린 클럭 속도에 일반적으로 영향 받지 않는다는 점이다. 물리적인 장치들을 에뮬레이터에서 동작하고 있는 가상 디자인에 연결할 경우, 그 클럭 및 데이터 전송속도는 에뮬레이터 내 디자인의 속도에 맞도록 낮춰야 하는데, 이는 대개 실시간에 비해 10~100배 느리다. 많은 장치들의 경우 이것은 까다로운 작업이 될 수 있다. 다행히도 JTAG의 클럭 속도를 에뮬레이터 속도에 맞춰 낮추는 것은 간단한 축에 속한다.
프로브를 사용하는 덕분에 소프트웨어 디버깅 작업은 물리적인 개발 보드를 사용해 소프트웨어를 실행하는 것과 똑같으며, 단지 약간 더 느릴 뿐이다. 코드를 디자인으로 다운로드하고 브레이크포인트을 설정할 수 있으며, 변수, 레지스터 및 메모리를 검토하고 변경할 수 있다. 개발자들은 디버깅 중인 코드를 연속 실행시키거나 혹은 한단계씩 실행시킬 수 있다.
그 한 예가 멘토 그래픽스의 Veloce2 에뮬레이션 시스템이다. 이 제품은 이러한 소프트웨어 디버깅 접근방법이 가능하도록 기존의 물리적인 JTAG 연결을 제공하는데, 이러한 물리적인 JTAG 연결에는 여러 가지 단점이있다.
첫째, JTAG 프로토콜은 거의 모든 클럭 속도를 수용하지만, 많은 프로브들이 클럭의 시작과 정지를 지원하지 못한다. 에뮬레이터가 시동되고 정지될 경우 프로브와의 연결이 끊어질 위험이 있는 것이다. 에뮬레이터는 하드웨어 개발자가 신호 트레이스를 업로드 하거나 하드웨어를 디버깅할 수 있도록 정지될 수 있으며, OVM이나 UVM 테스트벤치가 새로운 스티뮬러스들을 연산할 수 있도록 정지될 수도 있다. 테스트벤치가 보다 복잡해짐에 따라 이러한 상황은 보다 빈번하게 발생할 것이다.
두 번째 단점은 JTAG 연결이 내부에 직접적으로 연결되어 있어서 디버깅 중인 디자인의 자체에 영향을 미치게 된다는 것이다. 어떤 부류의 버그에서는 이것이 전혀상관 없다. 그러나 다른 부류의 버그에서는 중요한 문제가 될 수도 있다.
JTAG 프로브는 프로세서를 디버깅 모드에 놓고 순차적으로 명령을 내린 뒤 순차적으로 결과를 받음으로써 작업을 수행한다. 이 프로세스에 필요한 시간은 JTAG 스캔 체인의 길이에 좌우되는데, 이는 프로세서마다, 그리고 디자인마다 다르다. 단순한 연산 조차도 수십만 클럭사이클이 소요되며, 복잡한 연산이라면 수백만 클럭 사이클이 소요될 수 있다.
이는 하드웨어 디자인의 활동을 프로세스 내부의 소프트웨어에서 일어나고 있는 일과 연관시키기가 어렵다는 것을 뜻한다. 에뮬레이터는 이를 정지시켜서 하드웨어에서 무슨 일이 일어나고 있는지 들여다 볼 수 있다. 하드웨어가 정지되면 프로브가 사용하는 JTAG 클럭도 정지된다. 이는 하드웨어를 디버깅 하고자 들여다 볼 경우 소프트웨어 디버거는 정지되고 만다는 것을 뜻한다. 소프트웨어 디버거가 동작하고 있을 때는 하드웨어의 상태를 들여다 볼 수 없는 것이다. 게다가 JTAG의 내부에 직접 연결된다는 특성은 그것이 멀티코어 동기화 기능에 영향을미치는 동시에 멀티코어 실행하는 부분에 대한 디버깅도 어렵게 만든다.
가상 JTAG
물리적인 JTAG에 대한 대안은 프로브를 가상 JTAG연결을 통해 부착함으로써 첫 번째 제약 사항을 완화시키는 것이지만, 이는 두 번째 제약 사항을 완화시키지는 못한다.
인서킷 에뮬레이션(ICE: In-circuit Emulation)이라고 하는 기존의 방식과는 달리, 오늘날의 모든 에뮬레이션시스템들은 범용 컴퓨터에서 실행되고 있는 프로그램을 고속 통신 채널을 통해 에뮬레이터에 인터페이스 시킨 뒤, 에뮬레이터에 매핑된 DUT를 구동하고 신호를 샘플링하여 주고 받을 수 있다. 통신 채널 상에서 일련의 신호들을 구동 및 샘플링 하는 모듈을 종종‘트랜잭터(transactor)’라고 부르며, 이는 원격으로 연결된 호스트 컴퓨터 상에 있는 프로그램에 의해 제어된다. 그 한 예가 JTAG 트랜잭터로서, 이것은 소프트웨어 디버거가 에뮬레이터 내부의DUT에 있는 프로세서를 하나 이상 제어할 수 있도록 해준다. 이러한 연결은 물리적인 연결을 이용하는 물리적인 프로브와 동일한 기능 제공한다. 유일한 차이점은 디자인에 연결되는‘와이어’가 가상적 존재로서 물리적 실체가 아니라는 것뿐이다. 또한 디버거의 동작을 JTAG의 트랜잭션으로 변환하는 작업은 별도의 물리적인 프로브가 아니라 에뮬레이션 호스트 상에서 실행되고 있는 프로세스에 의해 수행된다.
물리적인 프로브 대신 가상 프로브를 실행하는 데 따른 이점들은 여러 가지가 있다. 첫 번째는 프로브에 대한 연결이 에뮬레이터의 시동 및 정지로 인해 방해 받지 않는다는 것이다. 에뮬레이터는 언제라도 시동 및 정지시킬 수있으며, 클럭 주파수는 소프트웨어 디버거에 대한 연결을 방해할 까봐 걱정할 필요 없이 변경할 수 있다.
보다 미묘한 두 번째 이점은 DUT를 에뮬레이터에 로드 할 때 주어지는 유연성이다. 오늘날의 에뮬레이터들은 다수의 디자인들을 동시에 로드 하여 실행할 수 있는 멀티유저차원의 시스템 자원이다. 디자인에 부착되는 I/O카드가 있을 경우에는 그 디자인이 외부 시스템에 연결되도록 하려면 특정 장소에서 로드 및 실행되어야만 한다. 그러나 물리적인 I/O를 없애면 해당 디자인은 사용 가능한 에뮬레이션 자원이 있는 어느 곳에서나 장소에 제약받지 않고 로드할 수 있다.
가상 프로브가 디자인 내부에 직접 연결되는 특성에따라, 이러한 디버깅 작업은 앞서 언급한 것과 동일한 제약 사항을 가지게 되는데, 이는 JTAG의 동작 방식으로 인한 결과로서 모든 JTAG 기반 솔루션의 제약사항이 될 수 밖에 없다. 예를 들어, 멘토 그래픽스의 Veloce2 에뮬레이션 시스템들은 ARM사의 VSTREAM 및 자사의 개발 제품과 동일한 가상 JTAG 연결을 지원한다.
프로세서 트레이스
JTAG 프로브 기술에 대한 대안은 트레이스 기반의 시스템을 이용해 에뮬레이터 상에서 실행되고 있는 프로그램을 디버깅하는 것이다. 기본적인 프로세서 트레이스는 프로세서에서 일어나고 있는 이벤트들의 현황표(tabular listing)이다. 일반적으로 이러한 트레이스들에는 실행된 명령어, 메모리 연산(주소와 데이터 값의 read/write와 같은) 및 레지스터 업데이트가 포함된다. 이 표를 봄으로써 소프트웨어 개발자는 프로세서의 활동을 추측하고 이를 다시 원래의 소스와 연관시킬 수 있다. ARM사의 DS5와 같은 일부 디버깅 환경들은 원래의 소프트웨어 소스에 자동으로 다시 연결시켜 주는 기능을 갖춘 트레이스 뷰잉(trace viewing) 툴을 제공한다. 프로세서 트레이스는 프로그램의 실행을 방해하지 않는 이점을 갖고 있다. 이것은 디버깅 대상 시스템의 실행에 영향을 미치지 않는다.
다음은 ARM 시스템의 에뮬레이션으로부터 얻은 프로세서 트레이스의 예제 중 하나이다:
프로세서 트레이스는 가장 기본적인 소프트웨어 디버깅 툴 중 하나로서, 소프트웨어 디버깅이라는 면에서 개선의 여지가 많다. 예를 들어, 심볼 정보나 해석 기능을 갖고 있지 않다. 사용자가 어떤 변수의 값을 알고 싶다면 검사대상 프로그램의 심볼 테이블을 수작업으로 해독한 뒤 이를 수작업으로 트레이스 정보와 연관시켜야 한다.
Codelink
멘토 그래픽스의 Codelink는 에뮬레이션이나 시뮬레이션과 함께 사용되는 소프트웨어 디버깅 환경이다. 트레이스를 기반으로 하는 이 제품은 프로세서의 상태에 대한 기존 디버거의 뷰를 포함하며, 모든 심볼 테이블 및 프로세서 상태에 대한 디코딩 작업을 수행한다. 트레이싱 기술을 기반으로 하기 때문에 실행중인 시스템의 동작에 끼어들거나 방해하지 않는다.
Codelink는 디자인 내 프로세서들의 RTL(register transfer level) 코드 내부와 주변의 신호들을 관찰함으로써 프로세서 상태를 추적한다. 표 형태의 트레이스 파일과 유사한 방식으로 프로세서들의 상태 변화를 기록하는데, 여기에는 실행되는 명령어, 메모리 트랜잭션 및 레지스터 업데이트가 포함된다. 이러한 상태 변화들은 binary형태의 압축된 데이터베이스로 저장된다.
Codelink의‘리플레이 서버(Replay Server)’는 이데이터베이스를 읽어 들임으로써 에뮬레이션이나 시뮬레이션 시 임의 시점에서 프로세서와 그 메모리 서브시스템의 상태를 재구성 해낸다. 리플레이 서버는 Eclipse와 같은 기존의 소프트웨어 디버깅 환경들에 접속할 수 있는데, 이 경우 Eclipse는 리플레이 서버의 클라이언트 역할을 하게 된다. 기존의 디버거 뷰는 단지 메모리와 레지스터 내용만으로 가득 차 있을 수 있으므로, 리플레이 서버는 가상 타겟 역할을 하여 디버거의 요청에 응답할 수 있다. 디버거는 메모리나 레지스터 값을 요청하게 되며, 이러한 값들을 해석하여 소프트웨어 개발자들에게 익숙한 디버깅 환경을 제공하게 된다.
이 밖에도 리플레이 서버는 클라이언트 디버거의 요청에 응답하여 step이나 run을 할 수 있다. 이 경우, 서버는 데이터베이스를 따라 진행하다가 메모리 및 레지스터의값을 실행 순서대로 제공한다. 디버거는 이러한 요청들의 결과를 이용하여 소프트웨어 디버거 뷰에 소스, 레지스터,메모리 및 변수 윈도우와 스택 또는 프레임 윈도우와 같은
개발자가 기대하는 내용들로 채워서 보여 줄 수 있다.
타겟의 상태는 트레이스 데이터베이스로부터 재구성 되므로 이러한 상태의 시간을 앞으로 전진시킬 수 있을 뿐만 아니라 거꾸로 후퇴시킬 수도 있다. 덕분에 최신 Eclipse 기반 디버거를 포함하여 백워드 디버깅 작업을 지원하는 디버깅 클라이언트들은 코드를 실행한 후에 단계별로 뒤로 나아갈 수 있다.
디버거의 시각에서 볼 때, 리플레이 서버는 개발 보드 또는 물리적 프로토타입과 다를 바 없어 보인다. 따라서 물리적인 타겟에 대해서와 마찬가지로 리플레이 서버에도 동일한 작업을 하고 동일한 결과를 보여준다. 대부분의 작업에 있어서 소프트웨어 개발자는 이를‘라이브 타겟’과 구분할 수 없을 정도로 유사하다.
리플레이 서버는 컴파일을 수반하지 않고도‘printf’ 문장을 사용자 임의로 넣고 뺄 수 있는 기능을 지원한다. 소프트웨어 개발자들은 흔히‘printf’문장을 디버깅 툴로 사용하여 레지스터, 변수 및 메모리의 값을 관찰하곤 한다. JTAG 및 기타 디버깅 방법에서는‘printf’명령을 내리려면 DUT를 재컴파일 및 재실행해야 한다. Codelink는 오프라인 디버깅 시에‘printf’문장을 임의로 추가할 수 있다. 사용자들은 백업을 한 뒤‘printf’를 추가함으로써 CodeLink 윈도우에서 즉각적인 결과 추출해 볼 수 있다.
이제까지 소프트웨어 개발자들은 에뮬레이션 시스템에서 디버깅 하려 할 때는 어느 정도 속도가 저하될 것을 예상하곤 했다. 타겟인 에뮬레이션 시스템이 실시간보다 10~100배 느린 속도로 동작하고 있기 때문이다.
Codelink는 에뮬레이션이 완료된 후에 리플레이 데이터베이스로부터 실행될 수 있으므로 100 MIPS의 실행 속도를 구현할 수 있다. 프로브 기반의 디버깅 환경처럼 순차적으로 교체되는 긴 명령어 시퀀스를 통해 프로세서를 제어할 필요가 없다.
또한 Codelink는 다수의 코어들 전반에 걸친 소프트웨어 뷰를 하드웨어 상태 파형(waveform) 뷰와 연결 시켜 보여 줌으로써 하드웨어와 소프트웨어의 동시에 디버깅할 수 있도록 도와준다. 이는 물리적 혹은 가상 프로브기반의 디버거 연결로는 불가능한 일이다.
Codelink의 한 가지 제약은 디버깅 중인 타겟의 상태를 변경할 수 없다는 것이다. 디버거 뷰는 디자인 내 프로세서들의 트레이스로부터 재구성되기 때문에 메모리나 레지스터 또는 변수를 새로운 값으로 설정한 뒤 새로운 상태에서 실행을 계속할 수가 없다. 즉, Codelink는 Readonly디버깅 환경인 것이다.
요약
임베디드 소프트웨어는 대부분의 SoC 디자인의 기능에 있어서 필수불가결한 일부분으로서 강력한 SoCvalidation 수단이 되었다. 개발 및 검증 단계에서 이를 고려하지 않는다면 경쟁 치열한 오늘날의 세계에서 개발자들은 불리한 위치에 처할 수 밖에 없다. Codelink는 에뮬레이션을 위한 최초의 오프라인 소프트웨어 디버깅 툴이다. 앞으로 점점 더 많은 임베디드 소프트웨어 디버깅이 에뮬레이션 세션 후에 오프라인으로 수행될 것이며, JTAG의 사용은 점점 더 줄어들 것이다. 지난 십여 년간 계속되어 온 작업 방식에 커다란 변화가 일어나고 있는 것이다. 그리고 이는 전자설계 분야에서 좋은 변화를 이끌어 내고 있음을 시사한다.
<반도체네트워크 8월>