EPNC(월간 전자부품 뉴스) UPDATED. 2018.12.14 금 17:43

상단여백
HOME EM FOUCS 포커스 뉴스레터
ROM(Flash) 메모리의 코드를 RAM에서 실행하기
이광재 기자 | 승인 2017.01.04 09:28

일반적으로 코어텍스-M 디바이스는 어플리케이션 프로그램이 ROM(flash) 영역에서 실행된다. 그러나 ROM과 RAM 메모리의 액세스 시간이 다르기 때문에 보다 빠른 처리를 위해 ROM에 있는 코드를 RAM 메모리로 복사해 실행하는 경우도 있다. 

또 부트로더에서 플래시 메모리의 전체 영역에 새로운 코드를 쓰려할 때는 플래시 메모리에 코드가 실행되고 있다면 오류가 발생할 수밖에 없다. 이런 경우 필요한 코드들이 모두 RAM으로 이동한 뒤 전체 플래시 메모리에 쓰는 작업을 해야 한다.  

ARM용 IAR 임베디드 워크벤치(Embedded Workbench for ARM, 이하 EWARM)에서 실행 코드들을 ROM에서 RAM으로 복사해 실행하는 방법에 대해 살펴본다. 

글  고성용 이사(Sung-Yong.ko@Iar.com)

자료제공   IAR시스템즈(www,iar.com)

__ramfunc 키워드
__ramfunc 키워드는 ROM에 위치한 함수를 RAM에서 실행하는 함수로 만든다. 이를 구현하기 위해서는 두 코드 섹션이 만들어진다. 하나는 RAM 실행을 위해(.textrw) 그리고 다른 하나는 ROM의 초기화를 위한 것이다(.textrw_init). 

만약 __ramfunc 로 선언된 함수가 ROM을 엑세스하려면 컴파일러가 경고가 발생한다. __ramfunc을 선언한 이유가 다른 경우라면 이러한 경고들은 안전하게 무시하거나 비활성화할 수 있다. 

__ramfunc 선언된 함수는 기본적으로 .textrw 섹션에 위치하고 실행된다. 사용 방법은 매우 간단하다. RAM에서 실행하려는 함수에 __ramfunc 키워드만 추가하면 된다.

[그림1]

main() 함수를 실행하기 전에 변수 초기화 작업을 하는 과정에서 __ramfunc 함수도 RAM에 위치되기 때문에 main()함수 이전에는 함수의 존재 상황을 알 수 없기 때문이다.

이니셜라이즈 바이 카피(initialize by copy)
애플리케이션에서 코드의 일부를 ROM(flash)에서 RAM으로 복사해 사용하는 경우도 있다. 이러한 경우 링커 컨피규레이션 파일(Linker Configuration File, .icf) 내용 중 이니셜라이즈 바이 카피(initialize by copy) 지시어에서 복사돼야 할 코드 섹션을 명시해 사용할 수 있다.

쉬운 방법은 특정 섹션에 적절한 함수를 위치시키는 것이다.(예를 들어 RAMCODE), 그리고 이니셜라이즈 바이 카피(initialize by copy) 지시어에 RAMCODE 섹션을 추가한다.

[그림2]

특정한 위치에 RAMCODE 함수들을 위치시키기 위해서는 각 함수에 대해 위치 지시어를 지정해 줘야한다. 그렇지 않은 경우 다른 읽기/쓰기(read/write) 섹션에 함께 위치할 수 있다.

[그림3]

오브젝트 파일의 코드를 RAM에서 실행
예를 들어 codeRAM.c에 포함되어 있는 함수들을 모두 RAM에서 실행하려 할 때 오브젝트(object) 명령어를 이용할 수 있다. 이 파일은 컴파일 한 결과가 codeRAM.o를 생성한다. [그림4]와 같이 icf 파일에 명시하면 codeRAM.o의 코드들을 모두 RAM으로 복사하여 RAM에서 실행한다.

[그림4]

RAM에서 모든 코드 실행
프로그램 시작시에 전체적인 애플리케이션을 ROM에서 RAM으로 복사하기를 원하는 경우에도 이니셜라이즈 바이 카피 지시어를 사용하면 된다.

[그림5]

읽기/쓰기 패턴은 초기화되는 변수에 대응되며 초기 스타트업시 변수들을 초기화한다.  리드오운리(readonly) 패턴은 모든 읽기 전용 코드 및 데이터에 대해 처리되며 초기화 작업에 필요한 코드와 데이터는 제외된다. 
__low_level_init() 함수는 초기화 작업이 이루어지기 전에 호출되므로 ROM에서 RAM으로 복사

되지 않는다. 그러므로 ROM에 코드가 초기화 작업 후에 남아 있지 않으려면 __low_level_init() 와 동일한 이름의 함수를 사용하지 말아야 한다.

만약 RAM으로 복사할 필요가 없는 내용들은 예를 들어 인터럽트 벡터 테이블과 같은 자료들, except 명령을 이용해 제외시킬 수 있다. 또 C++ 다이나믹 이니셜제이션 테이블(dynamic initialization table)도 RAM으로 복사하는 것을 제외시키는 것을 추천한다. 이는 일반적으로 한번 읽고 전혀 사용하지 않기 때문이다.

[그림6]

코어텍스-M 디바이스의 리셋 되는 과정을 살펴보면 [그림7]처럼 벡터 테이블의 첫 번째 위치한 값이 스택포인터다. 다음에 위치한 값이 프로그램 시작 지점이다. 하드웨어적으로 CPU가 리셋 되면 벡터 테이블은 ROM의 처음 위치에 있게 되고 이 어드레스에 있는 처음 값을 SP(Stack Pointer)에 설정하고 PC(Program Counter)가 두 번째 값인 Reset_Handler 주소를 갖게 된다. 이렇게 되면 애플리케이션이 Reset_Handler에서 시작하게 된다.

[그림7]

일반적으로 클럭 설정 등의 하드웨어 기본 초기 작업을 하고 변수 초기화 작업을 진행한다. 이때 ROM의 코드를 RAM으로 복사하는 작업이 이뤄진다. 해당 코드는 자동으로 실행 코드에 삽입되기 때문에 사용자가 작성할 필요는 없다.

[그림8]에서 EWARM에서 main() 함수를 실행하기 전까지의 수행 과정을 알 수 있다. EWARM에서는 기본적으로 제공되는 __iar_program_start라는 시작 라벨을 호출하면 __low_level_init()라는 함수를 호출한다. 함수명에서 알 수 있듯 저수준의 초기화 작업을 위한 함수다. 만약 리셋 후 시스템에 빠른 초기 설정 작업이 필요한 경우 이 함수를 이용해 코드를 작성하면 된다. 

__low_level_init() 함수 실행이 완료되면 변수 초기화 작업을 진행한다. 변수를 초기화하는 과정에서 ROM에 있는 실행 코드들을 RAM으로 복사해 함수가 RAM에서 동작할 수 있게 한다.
변수 초기화 작업 시 상수 데이터들이 많은 경우에는 크기를 줄이기 위해 압축 알고리즘이 동작해 자료를 압축하고 초기화 과정에서 압축을 해제하는 코드가 적용된다. 이러한 기능으로 좀 더 작은 크기의 실행 코드를 생성할 수 있다. 주의할 점은 사용자가 수동으로 변수를 초기화 하는 경우에는 압축 여부에 따라 알맞은 코드가 실행되도록 해야 한다.

[그림8]

참고로 ROM에서 실행하는 프로젝트에서 생성되는 ROM/RAM 사용량을 살펴보면 다음과 같다. ROM에서 RAM으로 코드를 복사해 실행하는 경우에는 읽기/쓰기 코드 메모리(readwrite code memory) 정보가 추가돼 RAM상에서 동작하는 코드 크기 정보를 보여준다.

[그림9] ROM에서 실행 시 메모리 사용
[그림10] ROM에서 RAM으로 코드를 복사해 실행하는 경우 메모리 사용

다음 [그림11]과 [그림12] 예제에서는 벡터 테이블을 초기 부팅에 필요한 최소의 벡터 테이블을 설정해 앞에서 거론한 복사하기에 필요한 코드를 실행하고 RAM에서 코드가 동작할 때 보다 효율적으로 실행될 수 있도록  벡터 테이블도 RAM에 위치시키도록 구현하고 있다.

[그림11]
[그림12]

다음은 ROM의 코드를 전체적으로 RAM에 복사해 실행하는 icf예제를 살펴본다. 이니셜라이즈 바이 카피 { readonly, readwrite };  명령을 사용하면 링크 과정에서 코드를 ROM에서 RAM으로 복사하기 위한 최소한의 코드만을 ROM에서 실행한다. 코드의 복사가 모두 완료되면 RAM에서 실행될 수 있다. 

[그림13]
[그림14]

[그림14] map파일에서 확인할 수 있듯 벡터 테이블과 ROM의 코드를 RAM으로 복사하기 위한 기본적인 기능의 코드만을 ROM에 유지하고(1) 나머지 코드들은 RAM으로 복사해 실제로 실행되는 어드레스는 RAM번지(3)를 가지고 있다. 

또한 벡터 테이블도 초기 부팅을 위한 벡터 테이블과 RAM으로 복사해 사용할 벡터 테이블을 구분해 설정한 부분(2)도 확인 할 수 있다.

맺음말
플래시 메모리에서 실행되는 것 보다는 RAM에서 실행되는 것이 필요한 경우가 있다. 빠른 실행을 구현하기 위해서나 코드가 있는 플래시 메모리를 지우고 다시 쓰는 경우에는 RAM에서의 실행 기능이 필요하다. 툴 자체에서 지원되는 이러한 기능을 잘 활용하면 편리하게 코드를 RAM에서 실행 시킬 수 있다. 

이광재 기자  voxpop@techworld.co.kr

<저작권자 © EP&C News, 무단 전재 및 재배포 금지>

이광재 기자의 다른기사 보기
icon인기기사
PREV NEXT

여백
여백
여백
여백
여백
icon
여백
여백
여백
신제품
여백
Back to Top