Заставить xc32-ld поместить весь код приложения в kseg0_boot_mem

Я написал приложение загрузчика PIC32MX. Я хотел бы сказать компоновщику, чтобы он помещал его полностью в загрузочную память, чтобы все пространство программы оставалось для конечного приложения.

В настоящее время то, что я считаю соответствующими частями моего .ldфайла, выглядит так:

_RESET_ADDR              = 0xBFC00000;  
_BEV_EXCPT_ADDR          = (0xBFC00000 + 0x380);
_DBG_EXCPT_ADDR          = (0xBFC00000 + 0x480);
_DBG_CODE_ADDR           = 0xBFC02000;
_DBG_CODE_SIZE           = 0xFF0     ;
_GEN_EXCPT_ADDR          = _ebase_address + 0x180;

MEMORY
{
  kseg0_program_mem    (rx)  : ORIGIN = 0x9D000000, LENGTH = 0x10000 /* All C Files will be located here */ 
  kseg0_boot_mem             : ORIGIN = 0x9FC00000, LENGTH = 0x1000 /* This memory region is dummy */ 
  exception_mem              : ORIGIN = 0x9FC01000, LENGTH = 0x200 /* Interrupt vector table */
  config3                    : ORIGIN = 0xBFC02FF0, LENGTH = 0x4
  config2                    : ORIGIN = 0xBFC02FF4, LENGTH = 0x4
  config1                    : ORIGIN = 0xBFC02FF8, LENGTH = 0x4
  config0                    : ORIGIN = 0xBFC02FFC, LENGTH = 0x4
  kseg1_boot_mem             : ORIGIN = 0xBFC00000, LENGTH = 0x2FF0 /* C Startup code */
  kseg1_data_mem       (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x8000
  sfrs                       : ORIGIN = 0xBF800000, LENGTH = 0x100000
  debug_exec_mem             : ORIGIN = 0xBFC02000, LENGTH = 0xFF0
  configsfrs                 : ORIGIN = 0xBFC02FF0, LENGTH = 0x10
}

Это сгенерированный по умолчанию скрипт компоновщика, для PIC32MX695F512H , хотя длина некоторых секций могла измениться — схема памяти чипа есть на странице 61 даташита.

Должен ли я просто изменить ORIGINи LENGTHна kseg0_program_memзначения kseg0_boot_memи указать компоновщику разрешить перекрывающиеся разделы? Это не кажется таким уж чистым. Есть ли способ сказать компоновщику, чтобы он поместил код приложения не в , kseg0_program_memа в kseg0_boot_mem?

Я только что прочитал об этом в этой электронной книге - я не могу ответить сам, но взгляните на страницу 44, и там может быть полезная информация.
Чуть ниже у вас, вероятно, есть что-то вроде «.text ORIGIN(kseg0_program_mem) :», которое сообщает компоновщику, что все в разделе .text должно находиться в сегменте kseg0_program_mem. Это не то, что я пробовал, но вы, вероятно, могли бы вместо этого изменить это на kseg0_boot_mem ...
Я понимаю, что спрашиваю здесь, но на форуме pic32 есть довольно приличные люди, которые хорошо разбираются в компоновщиках.

Ответы (2)

Компилятор C поместит код запуска среды выполнения C в файл kseg0_boot_mem, который устанавливает стек, кучу и общую инициализацию процессора. Количество размещаемого кода kseg0_boot_memбудет варьироваться между сборкой отладки и сборкой выпуска. Если я правильно помню, когда я работал над загрузчиком для PIC32MX250F, отладочная сборка занимала ~70% kseg0_boot_mem, чего было недостаточно для моего загрузчика.

Если ваш загрузчик достаточно мал, чтобы поместиться вместе kseg0_boot_memс кодом запуска C, уменьшите размер файла kseg0_boot_mem, а затем переместите kseg0_program_memего над новым boot_memпространством. Обратите внимание, что вы не можете переместить начальное местоположение пространства kseg0_boot_mem. Выполнение кода начинается 0xBFC00000с PIC32, и вы ничего не можете сделать, чтобы изменить это. Если вы хотите переместить весь загрузчик, вам также придется переместить таблицу ISR. Например:

MEMORY
{
  kseg0_program_mem    (rx)  : ORIGIN = 0xBFC01200, LENGTH = 0x1DF0 /* kseg1_boot is 2FF0 long.*/ 
  kseg0_boot_mem             : ORIGIN = 0x9FC00000, LENGTH = 0x1000 /* This memory region is dummy */ 
  exception_mem              : ORIGIN = 0xBFC01000, LENGTH = 0x200 /* Relocated ISR table. */
  config3                    : ORIGIN = 0xBFC02FF0, LENGTH = 0x4
  config2                    : ORIGIN = 0xBFC02FF4, LENGTH = 0x4
  config1                    : ORIGIN = 0xBFC02FF8, LENGTH = 0x4
  config0                    : ORIGIN = 0xBFC02FFC, LENGTH = 0x4
  kseg1_boot_mem             : ORIGIN = 0xBFC00000, LENGTH = 0x1000 /*This has been reduced in size.  Was 0x2FF0*/

  kseg1_data_mem       (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x8000
  sfrs                       : ORIGIN = 0xBF800000, LENGTH = 0x100000
  debug_exec_mem             : ORIGIN = 0xBFC02000, LENGTH = 0xFF0
  configsfrs                 : ORIGIN = 0xBFC02FF0, LENGTH = 0x10
}

ПРИМЕЧАНИЕ: это всего лишь пример сценария загрузчика, и его ни в коем случае нельзя копировать в рабочую среду!

При этом по опыту могу сказать, что пытаться впихнуть нетривиальный загрузчик в boot_memпространство программы не получится. Пространства, оставшегося от кода запуска C, обычно недостаточно, особенно если вам нужна тяжелая обработка ошибок и проверка (и да, вы ДЕЙСТВИТЕЛЬНО этого хотите!). Удаление отладочных сборок из очень ограниченного арсенала встроенных инструментов отладки тоже нехорошо. В какой-то момент в будущем вам нужно будет иметь возможность отлаживать аппаратное обеспечение. Я усвоил этот урок трудным путем.

Я рекомендую оставить kseg0_boot_memраздел кода в покое и просто работать с kseg0_program_memпробелом. Возьмите кусок kseg0_program_memсверху или снизу (не имеет значения) и используйте его для кода загрузчика и таблицы ISR. Оставьте себе место для расширения кода загрузчика. Работа с несколькими скриптами компоновщика немного утомительна.

Вместо того, чтобы делать все это в компоновщике, вы также можете сделать это аналогично этому

MEMORY
{
  kseg0_program_mem    (rx)  : ORIGIN = 0x9D000000, LENGTH = 0x5000
  bootverify_mem       (rx)  : ORIGIN = 0x9D03FFAC, LENGTH = 0x50
  kseg0_boot_mem             : ORIGIN = 0x9FC00490, LENGTH = 0xB70
  exception_mem              : ORIGIN = 0x9FC01000, LENGTH = 0x300
  kseg2_boot_mem             : ORIGIN = 0x9FC01380, LENGTH = 0xC80
  kseg1_boot_mem             : ORIGIN = 0xBFC00000, LENGTH = 0x490
  debug_exec_mem             : ORIGIN = 0xBFC02000, LENGTH = 0xFF0
  config3                    : ORIGIN = 0xBFC02FF0, LENGTH = 0x4
  config2                    : ORIGIN = 0xBFC02FF4, LENGTH = 0x4
  config1                    : ORIGIN = 0xBFC02FF8, LENGTH = 0x4
  config0                    : ORIGIN = 0xBFC02FFC, LENGTH = 0x4
  kseg1_data_mem       (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x10000
  sfrs                       : ORIGIN = 0xBF800000, LENGTH = 0x100000
  configsfrs                 : ORIGIN = 0xBFC02FF0, LENGTH = 0x10
}



SECTIONS
{
  .config_BFC02FF0 0xBFC02FF0 : {
    KEEP(*(.config_BFC02FF0))
  } > config3
  .config_BFC02FF4 : {
    KEEP(*(.config_BFC02FF4))
  } > config2
  .config_BFC02FF8 : {
    KEEP(*(.config_BFC02FF8))
  } > config1
  .config_BFC02FFC : {
    KEEP(*(.config_BFC02FFC))
  } > config0
}

PROVIDE(_DBG_CODE_ADDR = 0xBFC02000) ;
PROVIDE(_DBG_CODE_SIZE = 0xFF0) ;
SECTIONS
{

  .extra_prgm_mem :
  {
    *(extra_prgm_mem)
  } >kseg0_boot_mem

  .extra_prgm_mem2 :
  {
    KEEP(*(extra_prgm_mem2))
  } >kseg2_boot_mem
/*Linker continued*/

Затем в своем коде вы можете поместить каждую функцию туда, куда хотите.

int  __attribute__ ((section ("extra_prgm_mem2")))GetVersion(char * Info){
    int Result = (Info[4] - '0') *  1000;
    Result += ((Info[5] - '0') *  100);
    Result += ((Info[6] - '0') *  10);
    Result += Info[7] - '0';
}

BOOL __attribute__ ((section ("extra_prgm_mem")))BLMedia_LoadEncryptedFile(char *file_name) {
//Function info
}

Также обратите внимание, что если вы не используете никаких прерываний, вы можете получить еще один 0x1000 в пространстве. Кстати, если это не последовательный загрузчик, я не считаю это подходящим.