Перейти к содержанию
    

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

Тогда получается, что TLB нужно хранить в SDRAM?

И какие в этом проблемы? В моем примере так и сделано.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

И какие в этом проблемы? В моем примере так и сделано.

 

Единственное, надо чтобы TLB лежала в некешеруемой области sdram.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

 

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

 

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

 

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

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

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

Изменено пользователем ZED

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да проблем с этим нет. Вы не могли бы мне объяснить назначения доменов и соответственно битов 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))

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Единственное, надо чтобы TLB лежала в некешеруемой области sdram.

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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 и всего подобного.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

To ZED:

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Теперь возникли проблемы с 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 и Кэшах?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

 

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

 

    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. Типа, работает - не работает.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

 

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

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

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...