오픈 소스 게임을 32비트 마이크로컨트롤러에 포팅하는 방법 오픈 소스 게임을 32비트 마이크로컨트롤러에 포팅하는 방법
여기에 2008-12-18 00:00:00

마이크로컨트롤러의 성능이 증가하면서 1990년대에 PC의 프로세싱 성능을 필요로 했던 프로그램을 마이크로컨트롤러를 사용하여 실행할 수 있게 되었다. 게이밍 영역은 특히 이러한 발전의 영향을 받는다. 이제 그래픽 LCD와 32비트 ARM 마이크로컨트롤러를 탑재한 모바일 애플리케이션에서 PC로 실행했던 최초의 3D 게임을 구현하는 것이 가능하다.

 

 

오픈 소스 게임을 32비트 마이크로컨트롤러에 포팅하는 방법

 

 

글│Pierre Berquin, STMicroelectronics 엔지니어

 

 

1990년대에 접어들면서 게임이 컴퓨터 세계에 확산되기 시작했다. 최초의 3D PC 슈팅 게임인 울펜슈타인(Wolfenstein) 3D를 즐겼던 것을 기억할 수 있다. 울펜슈타인 3D는 1992년에 IdSoftware에서 선보였던 게임으로 Doom의 전신이라고 할 수 있다. 울펜슈타인 3D는 PC의 그래픽 성능이 이러한 종류의 3D 애니메이션을 개발하기에 충분하다는 사실을 입증했다. 1990년대 십대 시절을 보냈던 많은 사람들은 PC에 3D 세계를 재현했던 최초의 게임으로 울펜슈타인 3D를 생생히 기억할 것이다. 소스 코드는 1990년대 중반 인터넷에 공개되었으며 지금도 여전히 존재하고 있다. 이제 이 게임을 PC가 아닌 마이크로컨트롤러의 성능과 통합 기능을 사용하여 다시 실행시키려고 한다.

 

그림 1. 애플리케이션 보드에서 실행하는 울펜슈타인 3D

 


그림 2. 레이 캐스팅 모델 만들기



이 글은 울펜슈타인 3D의 소스 코드를 분석할 의도가 없음을 언급하고자 한다. 소스 분석은 이미 다양한 글에서 다루고 있다. 대신 이 글의 목적은 복잡한 코드를 새로운 플랫폼에 포팅하는 방법을 설명하는 데 있다. 그러나 이 게임의 구성은 충분히 훌륭하므로 설명은 흥미를 끌 것이다. 실제로 1992년에 울펜슈타인 3D는 3D 게이밍의 세계에 혁명을 일으켰다. 이 게임은 플레이어가 3D 환경에서 자유롭게 돌아다닐 수 있었던 최초의 게임이었다.

 

그림 3. 텍스처 및 스프라이트

 


이 게임에는 많은 텍스처와 스프라이트가 사용되기 때문에 그래픽은 소스 코드만큼 중요하다. 게임에 3D 화면을 연출하기 위해 그래픽은 레이 캐스팅(Ray Casting) 기법을 사용하여 스크린 위에 배치된다. 레이 캐스팅은 관찰 시점(POV: point of view)으로부터 반경을 투사하는 것으로 구성된다. 이를 가속화하기 위해 많은 트릭이 사용된다. 예를 들어 픽셀 스크린 위에 반경을 투사하기 위해 해당 반경과 가장 가까운 벽이 교차하는 지점을 찾기 위한 공간 검색이 수행된다. 울펜슈타인 3D에서 벽과 텍스처의 크기는 64 × 64 픽셀이다.


당시 게임은 엄청난 성공을 거두었지만 한계가 존재했다. 그중 하나는 벽은 모두 동일한 높이를 갖고 모두 90° 각도로 위치하며 비스듬히 서있는 것은 하나도 없었다. 이러한 한계는 소스 코드가 덜 복잡하다는 것을 의미하기 때문에 포팅을 용이하게 해줄 수 있다. 또 다른 한계는 바닥과 천장에 텍스처가 없다는 점이었다.


그럼에도 불구하고 최근의 32비트 마이크로컨트롤러 상에서 이 게임에 새 생명을 불어 넣어보기로 한다. 한 가지 필요한 요소는 게임을 호스팅할 애플리케이션 보드를 생성하는 것이다. 사용자의 시점에서는 오직 두 가지 요소, 240 × 320 TFT 컬러 스크린과 게이머가 울펜슈타인 3D 미로를 돌아다닐 수 있게 해주는 일련의 키만 보인다. 이 밖에도 마이크로컨트롤러는 스크린과 키를 관리한다. 이와 같은 종류의 스크린은 병렬 인터페이스(16비트 폭)를 사용하기 때문에 이러한 스크린을 구동할 수 있는 마이크로컨트롤러를 선택해야 한다.

 

 

소스 코드를 힘들이지 않고 포팅하는 방법

 

울펜슈타인 3D 소스 코드는 매우 복잡하다. 소스 코드가 복잡할수록 마스터하기가 더 어렵다. 이러한 이유로 이 애플리케이션을 새로운 타켓에 포팅하는 것은 어려운 작업이다. 시작하기 전에 네이티브 애플리케이션을 작성하는 데 사용된 언어가 포팅 가능한지, 그리고 이 언어를 위한 컴파일러를 새로운 타겟에 사용할 수 있는지를 아는 것이 중요하다. 울펜슈타인 3D는 C로 작성되었다. C 언어는 마이크로컨트롤러 영역에 널리 사용되고 있으며 많은 컴파일러와 디버거가 나와 있기 때문에 포팅이 용이하다.


C 언어는 논리적이고 투명한 방식으로 작성된다면 소스 코드를 멀티 타겟팅할 수 있다. 프로젝트 소스 파일의 구조는 하나의 고려사항이다. 방법은 그림 4에서 설명된다.

 

그림 4. 소프트웨어 아키텍처

 


그림 4에서 보이는 소프트웨어 방법은 네이티브 소스 코드 게임과 애플리케이션 보드에 의해 사용되는 물리층을 분리하고 있다. 포팅 과정에서 네이티브 소스 코드는 약간 수정해야 한다. 하드웨어를 사용하는 함수는 Portable 섹션에서 이동하고 수정해야 한다.


프로그램을 새로운 타겟에 포팅하고자 할 때 주요 질문은 “프로그램을 실행할 수 있는 새로운 타겟은 무엇인가?”이다. 이러한 요건을 이해하기 위해서는 주변기기의 종류와 수뿐만 아니라 메모리 크기(울펜슈타인 3D는 최소 500KB 프로그램 메모리와 96KB RAM 메모리가 필요하다)와 같은 소스 코드의 주요 특징을 알아야 할 필요가 있다.

 

 

32비트 마이크로컨트롤러가 대세

 

애플리케이션의 핵심은 32비트 마이크로컨트롤러가 되어야 한다. 울펜슈타인 3D를 실행하려면 레이 캐스팅 기법을 위한 산술 알고리즘을 수행할 수 있는 고성능과 스크린을 리프레시하는 빠른 실행을 필요로 하기 때문이다. 이러한 수준의 성능은 8비트 또는 16비트 마이크로컨트롤러에서는 달성하기 불가능하다. 또 다른 사항으로 레이아웃 보드를 간소화하기 위해 임베디드 프로그램 메모리(플래시)를 내장한 마이크로컨트롤러를 선택할 필요가 있다. 현재 시중에는 많은 32비트 마이크로컨트롤러가 나와 있지만 임베디드 애플리케이션의 표준으로 ARM 프로세서가 사용된다.


여기에서는 특별히 임베디드 애플리케이션을 위해 개발된 코어인 ARM CortexTM-M3 코어를 탑재한 ST마이크로일렉트로닉스의 STM32를 선택했다. 이제 이 새로운 ST마이크로일렉트로닉스의 STM32 32비트 플래시 기반 제품군과 특히 STM32F103ZE 제품을 살펴보기로 한다.

 

 

STM32F103ZE의 특징

 

STM32F103ZE는 2.0V~3.6V의 애플리케이션 전원으로 최대 72MHz 주파수에서 실행한다. 이 마이크로컨트롤러는 최대 512KB 플래시 메모리와 64KB RAM을 제공한다. 외부 메모리 컨트롤러 FSMC(flexible static memory contr-oller)는 STM32F10xxx 마이크로컨트롤러가 다양한 메모리(SRAM, NOR 플래시 메모리 등)에 인터페이싱할 수 있게 한다. FSMC에는 16개 데이터 라인과 26개 어드레스 라인이 있어 5개의 독립적인 메모리 칩 선택 핀을 사용하여 최대 64MB 메모리에 인터페이싱할 수 있다. 울펜슈타인 3D 애플리케이션 보드에서 이 인터페이스는 TFT 디스플레이와 외부 4MB SRAM 고속 비동기 메모리를 구동하는 데 사용된다. 키는 범용 IO로 직접 구동된다. 애플리케이션 보드는 LM317 가변 레귤레이터와 함께 3개의 1.2v 배터리로부터 3V에서 실행한다.


ST마이크로일렉트로닉스는 많은 예제의 STM32 기능 관리를 포함하는 매우 유용한 소프트웨어 라이브러리를 제공하고 있다. 이러한 포팅 목적을 위해 라이브러리를 사용하여 TFT 디스플레이를 위한 하드웨어 드라이버를 작성하였다. STM32 라이브러리는 www.st.com에서 다운로드할 수 있다.


그림 5에서 아키텍처 프로젝트를 볼 수 있다. 울펜슈타인 3D 폴더는 그림 5와 같은 2개의 서브 폴더로 구성된다. 폴더 Appli에는 IDE 프로젝트뿐 아니라 TFT 스크린과 같은 하드웨어 드라이버 소스가 포함되어 있다. 폴더에는 하드웨어 애플리케이션 보드(우리의 경우 STM3210E-EVAL)에 대한 정의가 들어 있다. 또 애플리케이션 보드 하드웨어와 IDE 프로젝트를 관리하는 데 사용되는 ST마이크로일렉트로닉스의  STM32 라이브러리가 들어 있다. 라이브러리 함수는 울펜슈타인 3D의 소스 코드에 의해 하드웨어 드라이버로 사용된다.


그림 5. 폴더 프로젝트 아키텍처



폴더 Source에는 울펜슈타인 3D의 네이티브 소스 코드가 포함되어 있다. 소스 코드의 어떤 명령이나 함수도 애플리케이션 보드 하드웨어와 직접 상호작용하지 않는다. 서브폴더 portable에는 게임의 네이티브 소스와 소스 코드가 실행되는 타겟의 하드웨어를 연결하는 함수가 들어 있다. 우리의 경우에는 서브폴더 STM3210E-EVAL이 있다. 이 폴더에는 애플리케이션 보드 하드웨어를 호출하는 함수가 들어 있다.

 

 

디스플레이 관리의 예

 

디스플레이 관리의 예를 살펴보자. 울펜슈타인 3D 소스 코드에는 VW_Up-dateScreen 함수가 포함되어 있다. 이 함수는 내부 비디오 버퍼의 내용에 따라 TFT 스크린을 업데이트하며, 이와 같은 업데이트는 TFT 스크린을 구동하는 데 필요하다. 따라서 이것은 폴더 portable/ STM3210E-EVAL에서 정의되어야 한다. VW_UpdateScreen 함수는 폴더 Appli/ STM3210E-EVAL에서 정의된 기본(드라이버) 함수들을 호출한다.


폴더 Source/portable/STM3210E-EVAL/에는 컴파일러와 호환되는 종류에 대한 간단한 설명과 정의가 있다. 이러한 방식에 따라 진행하면 복잡한 소스 파일을 변경하지 않아도 한 타겟의 소스를 다른 타겟에 포팅하는 것이 가능하다. 이것은 예를 들어 다른 인터페이스 하드웨어로 서로 다르게 매핑되는 STM32 애플리케이션에 소스를 전달하거나 컴파일러를 변경해야 하는 경우 유용하다. 새로운 타겟을 위해 Appli/STM3210E-EVAL/ 및 Source/portable/STM3210E-EVAL/에서 constraint 파일만 업데이트하면 된다.


그림 6에서 결과를 볼 수 있다. 90년에 나온 포켓 게임과 유사하게 보인다.
C로 작성된 이전 PC 게임의 소스 코드는 인터넷에서 쉽게 구할 수 있다. STM32 제품군의 마이크로컨트롤러 성능과 LCD 디스플레이가 통합되어 있는 덕분에 이들 게임은 이제 STM32를 기반으로 하는 애플리케이션에서 경험할 수 있다.

 

그림 6. 최종 애플리케이션

 

 

디지털여기에 news@yeogie.com <저작권자 @ 여기에. 무단전재 - 재배포금지>