Jump to content

    
Sign in to follow this  
ZED

MMU D-Cache I-Cache для ARM926EJ-S

Recommended Posts

И какие в этом проблемы?

Да проблем с этим нет. Вы не могли бы мне объяснить назначения доменов и соответственно битов AP?

 

Вот привожу, что у меня получилось:

 

Небольшие уточнения, правильно ли я понимаю: TLB располагаем в конце SDRAM, основную программу вначале (я для кэшируемой области памяти выделил первые 32 Мб), инициализируем ее как Write-Back, переферию делаем некэшируемой. Все, TLB готов!

 

Если я хочу задать переменную в некэшируемой области памяти, то беру адрес, для которого TLB = 0, ну например 0x2350 0000. Тогда объявляем указатель:

unsigned int *variable =  (unsigned int *) (0x2350 0000);
variable = 1234; // присваевыем, как пример, число переменной

P.S. SII, спасибо Вам за ссылку!

Edited by ZED

Share this post


Link to post
Share on other sites
Да проблем с этим нет. Вы не могли бы мне объяснить назначения доменов и соответственно битов AP?

Это для защиты памяти при многозадачной работе в общем адресном пространстве. Типа каждой задаче - свой домен, чужие объявляем недоступными.

 

Если я хочу задать переменную в некэшируемой области памяти, то беру адрес, для которого TLB = 0, ну например 0x2350 0000. Тогда объявляем указатель:

unsigned int *variable =  (unsigned int *) (0x2350 0000);
// [b]Забыта *[/b]
[b]*[/b]variable = 1234; // присваевыем, как пример, число переменной

Я бы порекомендовал использовать возможности компилятора:

#pragma location="NO_CACHE"
unsigned int variable;
variable = 1234; // А вот тут без звездочки

В файле конфигурации линкера надо объявить секцию NO_CACHE и разместить ее в соответствующих адресах.

В этом случае можно будет достаточно просто объявлять множество таких переменных, не занимаясь ручным заданием адресов

Кстати, даже первый вариант можно описать в виде:

#define variable (*(unsigned int *) (0x2350 0000))

 

Share this post


Link to post
Share on other sites

Чисто совет. Кэш - отличная штука. Ускоряет так нормально.

И если не мудрить, то просто работаешь как обычно.

Кэшируемая или не кэшеруемая память - это важно лишь в очень специфических случаях. В обычной жизни такие случаи не встречаются.

 

И еще не имеет особого смысла, особенно для 9260 кэшировать СРАМ. Ибо врядли вы там будете прямой доступ к памяти организовывать, а быстродействие кэша и СРАМ одинаковое. (Кэш срам полезен, когда в ней не только программа работает, но и область прямого доступа есть. Тогда программа работаетв кэше, а память свободна для DMA).

Share this post


Link to post
Share on other sites
Единственное, надо чтобы TLB лежала в некешеруемой области sdram.

Ни малейшей необходимости в этом нет.

 

P.S. TLB = Translation Lookaside Buffer, а таблица называется Translation Table.

Share this post


Link to post
Share on other sites

Блин код забыл прикрепить:

unsigned int AT91F_ARM_ReadControl()
{
   register unsigned int ctl;
   ctl = __MRC(15, 0, 1, 0, 0);
       return ctl;
}

void AT91F_ARM_WriteControl(unsigned int ctl)
{
    __MCR(15, 0, ctl, 1, 0, 0);
}

void AT91F_ARM_WriteTTB(unsigned int ttb)
{
   __MCR(15, 0, ttb, 2, 0, 0);
}
void AT91F_ARM_WriteDomain(unsigned int domain)
{
   __MCR(15, 0, domain, 3, 0, 0);
}


//-----------------------------------------------------------------------------
// Размер страницы = 4 Kб (0x1000)
// Раскладка по памяти:
// 0000 0000 - Boot Memory
// 0010 0000 - ROM, не используется (32 Кб)
// 0020 0000 - SRAM0 (4 Кб)
// 0030 0000 - SRAM1 (4 Кб)
// 0050 0000 - UHP (16 Кб)
// 2000 0000 - SDRAM (32 Mб)
// 4000 0000 - NAND DATA
// 4020 0000 - NAND ADDR
// 4040 0000 - NAND CMD
// FFF0 0000 - Периферия
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
// Описания секций:
// [1..0]  = "01";
// 2 - B - Bufferable;
// 3 - C - Cacheable;
// 4 - '1';
// [8..5] - Domain = "1111";
// 9 = '0';
// [11..10] - AP;
// [19..12] = "00000000"
// [31..20] - Базовый адрес секции

// Биты AP
//      01 - Нет доступа (No Access)
//      10 - Только чтение (Read-only)
//      11 - Чтение/Запись (Read/write)

// Биты C и B:
//      0   0 - Не Кэшируемая, Не Буферизируемая
//      0   1 - Не Кэшируемая, Буферизируемая
//      1   0 - Write-Trough-кеш
//      1   1 - Write-Back-кеш
//-----------------------------------------------------------------------------  

#define TLB_ADDR 0x2F000000 // Базовый адрес расположения TLB в памяти
#define TLB_NCNB 0xDF2      // Noncachable, Nonbufferable      11 0 1111 1 00 10
#define TLB_WT   0xDFA      // Write-through                   11 0 1111 1 10 10
#define TLB_WB   0xDFE      // Write-back                      11 0 1111 1 11 10

// Инициализация MMU:
void AT91F_InitMMU(void)
{
// TLB располагается в SDRAM 
 unsigned int   *TLB  = (unsigned int *) (TLB_ADDR);
 unsigned int i, ctl;

 // Инициализация TTB:
 AT91F_ARM_WriteTTB(TLB_ADDR); // Записать начальный адрес расположения TTB (CP15 c2)
 AT91F_ARM_WriteDomain(0xFFFFFFFF); // Domain Access Control Register (CP15 c3)

 // Очистка TLB:
 for (i = 0; i < 4096; ++i) TLB[i] = 0;

 // После Reamp по адресу 0x00000000 расположена SRAM0:
 TLB[0x000] = 0x00000000 | TLB_WB; 

 // После Reamp по адресу 0x00100000 расположена ROM:
 TLB[0x001] = 0x00100000 | TLB_NCNB;

 // SRAM1:
 TLB[0x003] = 0x00300000 | TLB_WB;

 // UHP:
 TLB[0x005] = 0x00500000 | TLB_WB;

 // Код основной программы, расположенный в SDRAM (32 Мб):
 for (i = 0x200; i < 0x200 + 31; i++){
   TLB[i] = (i << 20) | TLB_WB;
 }

 // Переферия:
 TLB[0xFFF] = 0xFFF00000 | TLB_NCNB

//Разрешить MMU
   ctl = AT91F_ARM_ReadControl();
   ctl |= (1 << 0);
   AT91F_ARM_WriteControl(ctl);
//Разрешить I-Cache
   ctl = AT91F_ARM_ReadControl();
   ctl |= (1 << 12);
   AT91F_ARM_WriteControl(ctl);
//Разрешить D-Cache
   ctl = AT91F_ARM_ReadControl();
   ctl |= (1 << 2);
   AT91F_ARM_WriteControl(ctl);
}

И еще не имеет особого смысла, особенно для 9260 кэшировать СРАМ

Т.е. эта строчка лишьняя:

  // После Reamp по адресу 0x00000000 расположена SRAM0:
  TLB[0x000] = 0x00000000 | TLB_WB;

 

Чисто совет. Кэш - отличная штука. Ускоряет так нормально.

И если не мудрить, то просто работаешь как обычно.

Кэшируемая или не кэшеруемая память - это важно лишь в очень специфических случаях. В обычной жизни такие случаи не встречаются.

 

Вот видимо у меня такой случай. Я все это делаю, чтобы запустить EMAC на вышеупомянутом контроллере. И вот в теме, которую я открыл, чтобы с ним разобраться EMAC AT91SAM9260. Так вот в этой теме мне сказали, цитирую:

дескрипторы должны быть в не кешируемой области.

Вот поэтому я так все дотошно и спрашиваю, хочу разобраться. Просто еще несколько месяцев назад я вообще не знал что такое ARM процессоры, IAR, J-Link и т.д. Не говоря уже о кэшах, MMU и всего подобного.

Share this post


Link to post
Share on other sites

Ну и что что в некэшируемой. Ставите нужный битик в описании нужной страницы и все. И она уже некэшируемая.

Всякие там буфера прямого доступа, оне приравниваются по своему сволочизму к аппаратным регистрам.

Share this post


Link to post
Share on other sites

To ZED:

 

У Atmel'a, чтобы не было проблем с когерентностью буферов и DMA надо просто все буфера для DMA объявить в некешируемой области. Для этого прислушайтесь к совету vmp. В чистом виде это относится и к EMAC (там еще особые требования по выравниванию адресов таблиц).

Share this post


Link to post
Share on other sites

Вообще, лучше все же применять творческий подход, а не рубить сразу - тут кэшируем, а тут не кэшируем. Во многих случаях может быть весьма уместен режим write-through (например, у framebuffer'а экрана), построчная или полная инвалидизация кэша (как раз при работе с буферами ПДП), залочка части программы/данных для критичных участков и т.п. Понятно, что сразу подобные упражнения могут и не понадобиться, но списывать их со счетов, один раз все настроив и забыв, совсем не стоит.

Share this post


Link to post
Share on other sites

Теперь возникли проблемы с PLL. Хотел протестировать работу MMU, для этого написал код дрыгания ножкой. В этом коде есть функция инициализации PLL:

  // Частота медленного RC-генератора SLCK 32.768 кГц. Период 1/32768 = 30.51 мкс
  // Максимальное время запуска основоного генератора: 75 мкс
  // Время запуска основного генератора:8 * OSCOUNT(=16) * 30.51 мкс = 3.9 мс
  // Запуск основного генератора:
  AT91C_BASE_PMC->PMC_MOR = (AT91C_CKGR_OSCOUNT & (0x40 << 8)) | AT91C_CKGR_MOSCEN;
  // Ждать пока пройдет время запуска:
  while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MOSCS));
  // Переключение блока задающей частоты на основную тактовую частоту
  AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_CSS_MAIN_CLK;
  
  // Настройка PLL на частоту 192 МГц:
  AT91C_BASE_PMC->PMC_PLLAR = ( AT91C_CKGR_SRCA                  // 29 бит = 1
                              | (0x2 << 14)                      // OUTA = 2
                              | (0xBF << 8)                      // PLLACOUNT = 191
                              | (AT91C_CKGR_MULA & (0x7C << 16)) // MULA = 124
                              | (AT91C_CKGR_DIVA & 12));          // DIVA = 12
  // Ждать пока пройдет время запуска:
  while(!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCKA));
  // Выбор задающей частоты и тактовой частоты процессора:
  // Предделитель тактовой частоты PRES = 1, Предделитель задающей частоты MDIV = 2.
  AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK | AT91C_PMC_MDIV_1;
  // Ждать пока пройдет время запуска:
  while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));
  // В качестве основной частоты использовать частоту PLL:
  AT91C_BASE_PMC->PMC_MCKR |= AT91C_PMC_CSS_PLLA_CLK;
  // Ждать пока пройдет время запуска:
  while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));

 

Проблема в том, что на строчке:

AT91C_BASE_PMC->PMC_MCKR |= AT91C_PMC_CSS_PLLA_CLK;

IAR выдает следующее:

Wed Dec 01 12:30:11 2010: The stack 'CSTACK' is filled to 99% (4087 bytes used out of 4096). The warning threshold is set to 90.%

Wed Dec 01 12:30:11 2010: The stack 'IRQ_STACK' is filled to 95% (92 bytes used out of 96). The warning threshold is set to 90.%

Полазил по форуму, там написано, что все дело в REMAP. Пробовал делать REMAP вручную:

AT91C_BASE_MATRIX->MATRIX_MRCR = AT91C_MATRIX_RCA926I | AT91C_MATRIX_RCA926D;

Все тоже самое. Помогите разобраться.

 

Кстати еще вопрос, с какой примерно частотой у меня должна будет дрыгаться ножка при включенном MMU и Кэшах?

Share this post


Link to post
Share on other sites

В жизни не получал таких варнингов от ИАР. Скорее всего потому, что стараюсь не передавать слишком много параметров в функции. И слежу за вложенностью...

 

Ремап никак не связан с варнингами. (Или это симулятор-отладчик такое выдает?)

 

Ремап надо делать или не делать в зависимости от надобности.

 

    B       __iar_program_start ; это должна быть первой строчкой вашего стартапа.

__iar_program_start:

/**********************************************************************
* ?CSTARTUP
*
* Execution starts here.
* After a reset, the mode is ARM, Supervisor, interrupts disabled.
*/
?cstartup:
        tst     PC, #0x300000; test for current map
        beq     _after_remap;

    mvn     r0, #0xFF        ;remap here
    bic     r0,r0, #0x1100
    mov     r1, #0x03
        str     r1, [r0, #+0]

_after_remap:

 

В этом коде проверяется где нах. программа и делается ремап если надо.

Ассемблера АРМ не знаю, делал наугад. Но работает железно.

 

----

По поводу ковыряния с кэшем - согласен с aaarrr - но только все делать последовательно. Сначала что по проще (написать и забыть), а уж потом, когда придет понимание процессов с одной стороны и нужда - с другой - то можно и потренироваться с управлением кэшем.

 

 

Про ножку. Смотря откуда код исполняется... В даташите гляньте - там должна быть указана частота тактирования портов. Вот больше нее - никак. (Если порты тут тактируются - не помню).

 

Лучше проверять по DBGU. Типа, работает - не работает.

 

Share this post


Link to post
Share on other sites
Ремап никак не связан с варнингами. (Или это симулятор-отладчик такое выдает?)

Именно он, когда дохожу до вышеуказанной строчки.

 

Скорее всего потому, что стараюсь не передавать слишком много параметров в функции.

Так функция и не содержит никаких параметров: void Init_CLK(void).

Share this post


Link to post
Share on other sites

Симуляторы и отладчики - зло.

Вообще тогда смотрите размер стека. Если по умолчанию, то там совсем маленькие стеки (0x10).

А если разрешены вложенные прерывания, то совсем будет плохо....

 

 

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this