2. 요구사항
FPGA 외부에서 microblaze용 프로그램을 SREC 형태로 다운로드하고 나면 microblaze은 부트로더를 이용해 해당 프로그램을 다시 원하는 위치에 재배치함으로써 프로그램을 실행 시켜야 합니다.
새로운 요구사항으로 다운로드된 프로그램의 실행이 끝나면 다시 부트로더로 돌아갈 수 있도록 유저 프로그램을 수정해야 합니다.
3. bootloader 분석
다음 리스트는 edk91에서 제공하는 부트로더의 소스 코드의 일부분 입니다.
static int8_t load_exec ()
{
int8_t ret;
void (*laddr)();
int8_t done = 0;
int32_t i;
srinfo.sr_data = sr_data_buf;
while (!done) {
if ((ret = flash_get_srec_line (sr_buf)) != 0)
return ret;
if ((ret = decode_srec_line (sr_buf, &srinfo)) != 0)
return ret;
#ifdef DISPLAY_PROGRESS
display_progress (srec_line);
#endif
switch (srinfo.type) {
case SREC_TYPE_0:
break;
case SREC_TYPE_1:
case SREC_TYPE_2:
case SREC_TYPE_3:
memcpy ((void*)srinfo.addr, (void*)srinfo.sr_data, srinfo.dlen);
break;
case SREC_TYPE_5:
break;
case SREC_TYPE_7:
case SREC_TYPE_8:
case SREC_TYPE_9:
done = 1;
ret = 0;
break;
}
}
print ("\r\nExecuting program starting at address: ");
putnum ((uint32_t)laddr);
print ("\r\n");
(*laddr)();
/* We will be dead at this point */
}
Load_exec() 함수에는 함수형 포인터가 선언되어 있습니다.
void (*laddr)();
이 함수형 포인터는 SREC을 디코딩 하는 도중에서 다음과 같은 코드로 초기화 됩니다.
laddr = (void*)srinfo.addr;
Load_exe() 함수 마지막 부분에 함수형 포인터가 지정된 함수를 실행 합니다.
print ("\r\n");
(*laddr)();
다음 리스트는 부트로더를 컴파일하고 역어셈블한 결과 입니다. 여기서 보면 microblaze의 리셋벡터 값인 0x0에서 0xb80800050이라는 코드가 실행되는되 이것은 0x50번지로 점프하라는 의미 입니다.
executable.elf: file format elf32-microblaze
Disassembly of section .vectors.reset:
00000000 <_start>:
0: b8080050 brai 80 // 50 <_TEXT_START_ADDR>
Disassembly of section .vectors.sw_exception:
00000008 <_vector_sw_exception>:
8: b80801b0 brai 432 // 1b0 <_exception_handler>
Disassembly of section .vectors.interrupt:
00000010 <_vector_interrupt>:
10: b80801a8 brai 424 // 1a8 <_interrupt_handler>
Disassembly of section .vectors.hw_exception:
00000020 <_vector_hw_exception>:
20: b80801b8 brai 440 // 1b8 <_hw_exception_handler>
Disassembly of section .text:
00000050 <_start1>:
50: 31a00ca0 addik r13, r0, 3232 // ca0 <_SDA_BASE_>
54: 30400b90 addik r2, r0, 2960 // b90 <_SDA2_BASE_>
58: 30201240 addik r1, r0, 4672
5c: b9f400c0 brlid r15, 192 // 11c <_crtinit>
60: 80000000 or r0, r0, r0
64: b9f4075c brlid r15, 1884 // 7c0 <exit>
68: 30a30000 addik r5, r3, 0
4. user application 분석
다음 리스트는 일반적으로 사용되는 프로그램 입니다.
void main()
{
print("xxxxxxxx -- Exiting main() --\r\n");
}
이 프로그램은 외부 메모리에서 실행되기 위해 링커스크립트가 만들어져 있습니다. 다음 리스트는 컴파일하고 역어셈블한 결과 입니다.
executable.elf: file format elf32-microblaze
Disassembly of section .vectors.reset:
00000000 <_start>:
0: b0008c00 imm -29696
4: b8080000 brai 0
Disassembly of section .vectors.sw_exception:
00000008 <_vector_sw_exception>:
8: b0008c00 imm -29696
c: b8080a7c brai 2684
Disassembly of section .vectors.interrupt:
00000010 <_vector_interrupt>:
10: b0008c00 imm -29696
14: b8080a98 brai 2712
Disassembly of section .vectors.hw_exception:
00000020 <_vector_hw_exception>:
20: b0008c00 imm -29696
24: b8080a94 brai 2708
Disassembly of section .text:
8c000000 <_start1>:
8c000000: b0008c00 imm -29696
8c000004: 31a01d70 addik r13, r0, 7536
8c000008: b0008c00 imm -29696
8c00000c: 30401c20 addik r2, r0, 7200
8c000010: b0008c00 imm -29696
8c000014: 30205da8 addik r1, r0, 23976
8c000018: b9f400e4 brlid r15, 228 // 8c0000fc <_crtinit>
8c00001c: 80000000 or r0, r0, r0
8c000020: b9f41254 brlid r15, 4692 // 8c001274 <exit>
8c000024: 30a30000 addik r5, r3, 0
앞에서 살펴본 부트로더의 분석결과와 비슷해 보이지만 0x0 번지와 0x04번지를 보면 0xb0008c00과 0xb80800000 명령어가 있습니다. Microblaze은 offset번지가 0xffff를 넘어가면 2개의 32비트 코드를 조합해서 명령어를 만드는데 이것을 분석해 보면 0x8c00_0000 번지로 점프하라는 의미 입니다.
그러면 0x00번지 저장되는 값은 부트로더에 의해서는 0xb8080050 이지만 부트로딩이 이루어지고 나면 0xb0008c00으로 바뀌게 됩니다
따라서 유저프로그램이 종료된 후 다시 부트로더로 돌아가기 위해서는 다음과 같이 수정된 리스트가 필요 합니다.
void main()
{
void (*laddr)();
print("xxxxxxxx -- Exiting main() --\r\n");
laddr = (void (*)())0x50;
(*laddr)();
}
이 코드가 보여주는 것은 처음 0x0 번지에 저장된 0xb8080050이 jump 한 번지인 0x50번지로 강제로 jump 하라는 것 입니다. 그러면 부트로더는 다시 동작을 하게 됩니다.
다음 그림은 부트로더가 유저 어플리케이션을 실행한 후 다시 부트로더를 실행하는 것을 보여주고 있습니다.
'edk' 카테고리의 다른 글
특정 메모리 공간에 데이터를 배치하는 attribute (0) | 2012.02.10 |
---|---|
xilinx 13.4 sw device driver & example (0) | 2012.02.10 |
float value를 string으로 바꿔주는 함수 및 사용법 (0) | 2012.01.10 |
특정번지에 위치한 함수를 주소로 강제로 호출하는 방법 (0) | 2012.01.06 |
SP605, reconfiguration, icap을 사용시 주의할 점 (0) | 2011.12.08 |