TMS320/Study2014. 8. 7. 15:51

굉장히 길다!

 

결과파일(.out)이 생기는 일련의 과정이 어떻게 되냐하면

C로 작성된 코드가 컴파일러를 거쳐 어셈블리 파일이 되고 어셈블리 파일이 어셈블러를 거쳐서 오브젝트 파일이 된다.

 

C파일->[컴파일러]->어셈블리 파일->[어셈블러]->오브젝트 파일

 

오브젝트 파일은 기계어로 이루어져 있을 것인데, 주소 정보를 포함하고 있지 않아 마이크로프로세서에서 실행될 수 없다.

이때! 링커가 오브젝트 파일을 입력으로 받아, 개발자가 정의한 메모리 배치 정보를 토대로 주소 정보를 부여하며 결과 파일을 만들어 낸다.

 

정리

1.컴파일러 : C파일을 어셈블리 파일로

2.어셈블러 : 어셈블리 파일을 오브젝트 파일로

3.링커 : 오브젝트 파일에 주소 정보를 부여하고 결과 파일 생성

 

================================================================

링커 커맨더 파일 이용하여 링커에 지시를 보낼 수 있는데 이 링커 커맨더 파일을 cmd라고 한다.(commander)

 

DSP에서 요구하는 링커 커맨더 파일은 단순하다.

cmd파일은 '메모리 정의' 부분과 '섹션 배치' 부분으로 이루어져 있다.

메모리 정의 부분은 시스템이 가지고 있는 메모리 자원을 기술하였으며

섹션 배치 부분은, 컴파일러나 개발자가 작성한 섹션을 앞의 메모리 정의 부분에 배치하는 것을 지시한다.

 

정리

1.cmd(command)파일 : 링커에 지시를 보낸다

2.cmd의 '메모리 정의'부분 : 시스템의 메모리 자원을 기술

3.cmd의 '섹션 배치' 부분 : 섹션을 메모리 정의에 배치

================================================================

2812_RAM_Ink.cmd을 살펴보자.

 

MEMORY
{
PAGE 0 :
   
   RAMM0      : origin = 0x000000, length = 0x000400
   BEGIN      : origin = 0x3F8000, length = 0x000002            
   PRAMH0     : origin = 0x3F8002, length = 0x000FFE
   RESET      : origin = 0x3FFFC0, length = 0x000002          

        
PAGE 1 :

 

   RAMM1    : origin = 0x000400, length = 0x000400
   DRAMH0   : origin = 0x3f9000, length = 0x001000        
}

 

 

위의 코드는 메모리 영역을 기술하고 있다. 몇가지 지켜야 할 규칙이 있는데 PAGE0에는 '코드 성격의 섹션'이 배치될 영역을 잡아주고 PAGE1에는 데이터 성격의 섹션이 배치될 영역을 기술한다.

28X는 단일 메모리 구조라 엄격히 구분할 필요는 없다고 한다.

 

또한 영역의 크기를 기술할 때, 시작번지길이함께 기술해야 한다.

 

RESET은 코드성격의 섹션으로 2비트이며 아래의 메모리맵에서 찾을 수 있다.

 

 

만약 PAGE0에 아래와 같이 작성되어 있다고 생각해보자.

EXDRAM    :    origin = 0x100000, length = 0x006000

 

EMIF(External Memory Interface 회로)가 접근 가능한 Zone0에서 7중 6에 크기 0x006000 만큼을 EXDRAM이라는, 데이터 영역이 배치될 메모리로 잡았다.

 

 

정리

1.PAGE0 : 코드 성격의 섹션을 배치할 메모리

2.PAGE1 : 데이터 성격의 섹션을 배치할 메모리

3.섹션 영역의 배치를 할 메모리를 잡을 때, 시작번지와 길이를 기술해야 한다.

================================================================

SECTIONS
{

   codestart        : > BEGIN,       PAGE = 0
   ramfuncs         : > PRAMH0       PAGE = 0 
   .text            : > PRAMH0,      PAGE = 0
   .cinit           : > PRAMH0,      PAGE = 0
   .pinit           : > PRAMH0,      PAGE = 0
   .switch          : > RAMM0,       PAGE = 0
   .reset           : > RESET,       PAGE = 0, TYPE = DSECT /* not used, */
  
   .stack           : > RAMM1,       PAGE = 1
   .ebss            : > DRAMH0,      PAGE = 1
   .econst          : > DRAMH0,      PAGE = 1     
   .esysmem         : > DRAMH0,      PAGE = 1

    
}

 

섹션 배치 부분이다. 코드에서 정의된 섹션을 위 MEMORY{ } 부분에 정의된 영역에 배치하는 것을 지시한다.

 

 codestart        : > BEGIN,       PAGE = 0
위 지시의 의미는 codestart 라는 섹션을 BEGIN이라는 영역에 주입할 것을 지시한다. 또한 PAGE0에 정의된 영역이라고 알려주고 있다.

 

참고로 codestart는 DSP281x_CodeStartBranch.asm에 선언되어 있다.

BEGIN의 크기는 고작 2word이다. 이는 이 섹션으로 이름 붙여진 코드가 LB _c_int00뿐이며 그 코드의 크기가 2word에 불과하기 때문이다.

 

<대충읽기>

앞서 배웠듯이 _c_int00는 rts2800_ml.lib에 있기 때문에 _c_int00가 수행하면 반드시 rts2800_ml.lib으로 분기하게 되고 그 내용을 실행한다.

MEMORY{ }을 보면 0x3F8000으로 잡혀있는데, 핸드북 47페이지의 부트모드를 보면 0010의 부트모드일 경우 H0 SARAM주소 0x3F8000으로 바로 점프함을 알 수 있다. 이 H0에 대한것 역시 34페이지(또한 56페이지)에 나와있다. 0010모드는 H0에서 코드를 시작하게 하여 시스템 개발 과정을 신속하고 편리하게 할 수 있도록 도모한다.

 

조금만 더 간단히, 설명하자. 위에 내용은 너무 헷갈릴 수 있다.

 

MC모드 기준으로 설명한다.

 

1. 우리가 부트모드를 0010으로 설정했다고 하자. 리셋 신호가 인가된 DSP는 리셋 벡터에 의해 부트로더를 실행시킨다.

2. 부트로더는 핀 설정 상태가 0010임을 감지하고 부트로더 수행을 마친 후 이에 따라 H0 SARAM으로 즉, 0x3F8000으로 분기하게 된다.

3. 0x3F8000번지에 codestart라는 섹션이 넣어져 있다.

4. codestart섹션에서는 LB _c_int00 코드를 실행하라고 한다.

5. 위 코드가 실행되어 _c_int00 즉, rts2800_ml.lib가 어디에 있던(플래시 메모리던, 외부 메모리던) 정확히 호출한다.

6. rts2800_ml.lib가 호출되어 프로그램이 수행될 수 있도록 칩 상태를 정비한 후, main()함수를 호출한다. 

 

.reset의 경우 뒤에 TYPE=DSECT라고 되어있다. DESECT는 앞서 선언한 내용을 '무효로 한다'고 지시한다.

이 RESET은 0x3FFFC0으로 리셋벡터를 가리킨다. 또한 이 리셋벡터는 TI가 마스킹 해놓은 변경불가 영역이다. 즉 이 리셋벡터에 대하여 새로 선언한 내용이 쓸모가 없고 그럴 필요도 없다는 것이다.

 

================================================================

링커의 과정을 아래와 같이 기술한다.

 

 

 

앞서 언급했듯이 링커커맨더 파일을 통해 링커에 지시를 내릴 수 있다.

링커는 오브젝트 파일에 주소 정보를 부여하고 결과 파일(.out)을 생성한다. 또한 링커과정을 보고하는 문서 파일인 map파일 생성한다.

 

================================================================

◎DSP281x_Headers_nonBIOS.cmd

 

역할 : BIOS를 사용하지 않는 상태(nonBIOS)의 MMR을 선언한 헤더(Headers)와 관계된 메모리 정의 및 섹션배치(cmd).

 

BIOS를 사용하는 경우 DSP281x_Headers_BIOS.cmd를 사용하면 된다.

파일의 내용을 살펴보자

 

 

 

 

메모리 배치에 있어서 프로그램 영역은 텅 비어있고 데이터 메모리만이 있다. MMR은 C언어에서 모두 데이터로 취급되기 때문이다.

 

예를들어 ADC부분을 보자.[순서대로 확인하면 이해하기 쉽습니다.]

☞Page1에 있는 ADC는 0x007100번지에 0x00020길이만큼 메모리를 배치받았다.

☞또한 SECTION 부분을 보면 AdcRegsFile 이라는 섹션을 ADC영역에 주입함을 알 수 있다.

☞이 AdcRegsFile섹션은 DSP281x_GlobalVariableDefs.c에서 전처리기(pragma)에 DATA_SECTION이라는 함수를 통해 선언되어 있다.(AdcRegFile섹션을 AdcRegs라고 명명했음)

☞또한 아래에 volatile struct ADC_REGS AdcRegs;로 ADC_REGS구조체로 데이터형을 대입하였다.

☞DSP281x_Adc.h에는 구조체로 정의된 ADC관련 MMR이 정의되어 있다. (struct ADC_REGS를 볼 수 있으며 그와 관련된 struct, union구조체를 확인할 수 있다.)

 

정리하자면, cmd를 통해 메모리를 배치하고 섹션을 배치하였으며, DSP281x_GlobalVariableDefs.c에서 이를 AdcRegs라고 데이터섹션으로 새로 명명하였다. 그리고 이를 다시 DSP281x_Adc.h에서 선언되어 있는 ADC_REGS의 구조체 데이터형으로 대입하였다. 우리는 이 구조체에 접근하는 것으로 레지스터를 조작할 수 있다. 

 

정리

1.DSP281x_Headers_nonBIOS.cmd은 nonBIOS의 MMR을 선언한 헤더와 관계된 메모리 정의 및 섹션배치를 위한 링커커맨더 이다.

2.MMR은 C언어에서 모두 데이터로 취급된다.

 

P.S : 그 외에도 DSP281x_SysCtrl.c에 명시되어 있는 ramfuncs 역시 선언되어 있다.

'TMS320 > Study' 카테고리의 다른 글

28계열의 MMR선언 및 조작(1)  (0) 2014.08.11
MMR이란?  (0) 2014.08.08
DSP281x_GlobalVariableDefs.c  (0) 2014.08.07
DSP281x_Device.h  (0) 2014.08.07
DSP281x_SysCtrl.c <좀더 자세히>  (0) 2014.08.06
Posted by 십자성군