Jump to content

    
Sign in to follow this  
mantech

Cortex A7 и А8, А9 Различия в запуске MMU и кэшей

Recommended Posts

19 часов назад, Integro сказал:

Если все три бита стоят, значит кеш должен работать, нужно регионы проверять

Ну и артифакты на экране вроде как косвенный признак. Кстати они должны быть? В коде еще нет соответвующего менежмента?

Еще б знать как... До сих пор не могу найти вменяемое описание этой долбаной таблицы TTB, которая. Досада в том, что на А9 и А8 все работало, как говорится, из коробки, никаких вопросов, тут какой-то гемор возник, может из за 2хядерности, хотя второе ядро не использую... 

С экраном была такая вещь, еще на А9м, когда с дуру закэшировал экранную область, появились артефакты в виде полосочек в 8 или 16 пикселей, потом понял, что ступил и перевел страницы в режим буфера, после этого все стало норм, тут же, пока D кэш отключен артефактов нет, включаю - появляются, распределение памяти не менял, вообщем х.з....

 

image.png.7f5cecb72c991438ffa6ac7a4e84f587.png

 

Вот поле под названием "Section"- похоже на таблицу ММУ, только вот что означают все эти битики?...

 

 

 

ЗЫ. Вообщем, методом "научного тыка" таки смог увеличить быстродействие с 200 попугаев до 3500, т.е. больше, чем в 10 раз. Думаю, это заслуга того, что кэш данных заработал, но тут есть несколько странных моментов, которые я понять не могу:

1) Заработало после того, как я поставил в 1 флаг B (buffering) вместе с флагом (С) кэширование. В А8 и А9 этого было делать не нужно. 

2) Артефакты в графике - тут вообще странно. В А8 и А9 для ускорения печати текста включил режим буфера для экранной области, проверил на рисовании закрашенного прямоугольника программным способом, На А8 при отключенном буфере 350 усл отсчетов, при включенном - 70, т.е. прирост заметный, затем включил бит кэша, стало 50, т.е. еще быстрее, без артефактов.

На А9 другая история, прирост включения буфера был, но не настолько (150 вместо 400), но включение кэша дало артефакты, хоть и ускорило до 100. Что в принципе логично, т.к. экранную область кэшировать не рекомендуется.

А на этом А7 при сброшенных битах кэша и буфера, получаю 70 ед. т.е. как-будто буфер уже включен, думал, может там флаг инверсный, но установка его в 1 ничего не дает вообще, установка флага кэша - ускоряет, но артефачит. Вообщем какое-то поле чудес...

Edited by mantech

Share this post


Link to post
Share on other sites
On 8/10/2019 at 2:10 AM, mantech said:

Что в принципе логично, т.к. экранную область кэшировать не рекомендуется

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

 

С A7, A9 не работал, но с ядром ARM9 пришлось в своё время повозиться (был вот такой динозавр: AT91RM9200).  Ниже код инита MMU лишь только с целью включить Data Cache. Виртуальные адреса совпадают с физическими (мне было так удобнее).  Для перифералов (дисплей, синтезаторы звука,...) кеширование не было включено, но был включен некий Bufferable (внятное назначение узнать не удалось, но он давал увеличение быстродействия при отрисовки на дисплей):

 

#define MMUTable (SRAM_Address+0x001FC000) //Базовый адрес First-Level Translation Table, выровнен на границу 16 kB

u32 PrepareMMU(void) //Заполняем First-Level Translation Table, бит 3 - Cache, бит 2 - Buffer
{
 *(u32*)(MMUTable+(0x000<<2))=0x00000C1E; //Internal SRAM after ReMap CB
 *(u32*)(MMUTable+(0x001<<2))=0x00100C1E; //Manufacturer ROM          CB
 *(u32*)(MMUTable+(0x002<<2))=0x00200C16; //Internal SRAM             B
 *(u32*)(MMUTable+(0x100<<2))=0x10000C1E; //External SRAM first MB    CB
 *(u32*)(MMUTable+(0x101<<2))=0x10100C1E; //External SRAM second MB   CB
 *(u32*)(MMUTable+(0x200<<2))=0x20000C16; //FM/WT Synthesizer         B
 *(u32*)(MMUTable+(0x300<<2))=0x30000C16; //MPU401                    B
 *(u32*)(MMUTable+(0x400<<2))=0x40000C16; //OLED                      B
 *(u32*)(MMUTable+(0xFFF<<2))=0xFFF00C12; //Internal Peripherals      -
 return MMUTable;
}

Включение кешей, MMU:

 

;MMU
 IMPORT PrepareMMU
 BL     PrepareMMU ;Return First-Level Translation Table Address in R0
;Write First-Level Translation Table Address
 MCR    p15,0,R0,c2,c0,0
;Write Domain
 LDR    R0,=0x00000003
 MCR    p15,0,R0,c3,c0,0
;Enable ICache, DCache, MMU
 LDR    R0,=0x4000507D
 MCR    p15,0,R0,c1,c0,0
;Enter the C code
 IMPORT __main
 BL     __main

 

P.S. Тема интересная, буду следить за дальнейшим её ходом :)

Edited by __inline__

Share this post


Link to post
Share on other sites

Кстати, в современном cmsis включено куча оберток вокруг обращений к  cp15.

Дисплей тут фреймбуфер обсуждается... ему в общем-то на последовательность  всеравно. Главное - чтобы дошло до памяти. А пробовали cleandcachebyaddr или еще как?

Edited by GenaSPB

Share this post


Link to post
Share on other sites

Еще я сталкивался с тем что перед включением надо вручную кэш инвалидировать. Иначе все что было после ресет вываливается в память... как работает после этого понятно. Кстати в cmsis теперь есть и на эту тему код.

Share this post


Link to post
Share on other sites
1 hour ago, GenaSPB said:

Кстати, в современном cmsis включено куча оберток вокруг обращений к  cp15.

Да, есть такое. Сейчас наблюдается нездоровая тенденция скрывать фундаментальные знания. Скоро разучатся писать на Си, не говоря уже об Ассемблере.  Зато облака будут и питоны... И призмы, гуглы с ФБР месте взятые и штрих-коды на лбу... Не за горами это будущее.  К сожалению.

 

Quote

 А пробовали cleandcachebyaddr или еще как?

Из того что мне нужно было: сбрасывал из кеша в память для ДМА по SPI. (Clean DCache, Flush)

 

Quote

Еще я сталкивался с тем что перед включением надо вручную кэш инвалидировать. Иначе все что было после ресет вываливается в память... как работает после этого понятно. Кстати в cmsis теперь есть и на эту тему код.

Не сталкивался с таким. На всякий случай добавлю, что тот код выше запускался во внутренней RAM контроллера,  изначально кеширование и ММУ были запрещены.  Внешняя память - 16-битная SRAM от Cypress на 2 МБ. (Не SDRAM).  Проект старенький - 2008 года. Стартап - простой до безобразия:

 

;Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
Mode_SVC EQU 0x13
Mode_IRQ EQU 0x12
Mode_FIQ EQU 0x11
I_Bit EQU 0x80 ;When I bit is set, IRQ is disabled
F_Bit EQU 0x40 ;When F bit is set, FIQ is disabled
;Stack Configuration (Stack Sizes in Bytes)
SVC_Stack_Size EQU 0x00000100
IRQ_Stack_Size EQU 0x00000100
FIQ_Stack_Size EQU 0x00000000
Stack_Size EQU (SVC_Stack_Size+IRQ_Stack_Size+FIQ_Stack_Size)
 AREA STACK,NOINIT,READWRITE,ALIGN=3
Stack_Mem SPACE Stack_Size
Stack_Top EQU Stack_Mem+Stack_Size
 PRESERVE8
;Area Definition and Entry Point
 AREA RESET,CODE,READONLY
ARM
;Exception Vectors
 LDR    PC,=Reset
Undef
 LDR    PC,=Undef
SWInt
 LDR    PC,=SWInt
PAbt
 LDR    PC,=PAbt
DAbt
 LDR    PC,=DAbt
 NOP
 LDR    PC,[PC,#-0xF20] ;IRQ
 LDR    PC,[PC,#-0xF20] ;FIQ
;Reset Handler
Reset
;Setup Stack for each mode
 LDR    R0,=Stack_Top
;Enter FIQ Mode and set its Stack Pointer
 MSR    CPSR_c,#Mode_FIQ:OR:I_Bit:OR:F_Bit
 MOV    SP,R0
 SUB    R0,R0,#FIQ_Stack_Size
;Enter IRQ Mode and set its Stack Pointer
 MSR    CPSR_c,#Mode_IRQ:OR:I_Bit:OR:F_Bit
 MOV    SP,R0
 SUB    R0,R0,#IRQ_Stack_Size
;Enter Supervisor Mode and set its Stack Pointer
 MSR    CPSR_c,#Mode_SVC
 MOV    SP,R0
 SUB    R0,R0,#SVC_Stack_Size
;CLK
 IMPORT PrepareCLK
 BL     PrepareCLK
;EBI
 IMPORT PrepareEBI
 BL     PrepareEBI
;SPI
 IMPORT PrepareSPI
 BL     PrepareSPI
;PIO
 IMPORT PreparePIO
 BL     PreparePIO
;MMU
 IMPORT PrepareMMU
 BL     PrepareMMU ;Return First-Level Translation Table Address in R0
;Write First-Level Translation Table Address
 MCR    p15,0,R0,c2,c0,0
;Write Domain
 LDR    R0,=0x00000003
 MCR    p15,0,R0,c3,c0,0
;Enable ICache, DCache, MMU
 LDR    R0,=0x4000507D
 MCR    p15,0,R0,c1,c0,0
;Enter the C code
 IMPORT __main
 BL     __main
;User Initial Stack & Heap
 AREA |.text|,CODE,READONLY

 EXPORT __user_initial_stackheap

__user_initial_stackheap
 EOR    R0,R0
 LDR    R1,=(Stack_Mem+SVC_Stack_Size)
 EOR    R2,R2
 LDR    R3,=Stack_Mem
 BX     LR

 END

 

 

 

Edited by __inline__

Share this post


Link to post
Share on other sites
3 часа назад, __inline__ сказал:

но был включен некий Bufferable (внятное назначение узнать не удалось, но он давал увеличение быстродействия при отрисовки на дисплей):

В этом режиме при записи в память нескольких значений, последовательно, включается DDR Burst, поэтому идет ускорение, но только записи в память, чтение тут никакого ускорения не дает...

3 часа назад, __inline__ сказал:

Я бы сказал, что не то что не рекомендуется, а её вообще нельзя кешировать

Да я понимаю, но странное дело, в кортексе А8 (процы А10, А13) включение кэша экранной области не нарушало ничего, и добавляло скорости работы, может там организация кэша была сделана по-другому, или дисплейный модуль был подключен напрямую к ДДР, а не через кэш, как в А9 или А7 кортексах...

Или может даже такая штука, т.к. включен режим кэша и буфера одновременно, при записи в экранную память происходило кэширование и сброс буфера в память одновременно, поэтому я мог и читать и писать в экранную область, используя кэш, но данные в дисплей отправлялись тоже корректно...

Edited by mantech

Share this post


Link to post
Share on other sites
3 minutes ago, mantech said:

В этом режиме при записи в память нескольких значений, последовательно, включается DDR Burst, поэтому идет ускорение, но только записи в память, чтение тут никакого ускорения не дает...

Спасибо, буду знать.

На счёт чтения, не представляю себе пользы чтения видеопамяти дисплея.  Всегда заводил промежуточный буфер и делал там все операции - по альфа-смешению и прочее - в системной памяти (которая кеширована на чтение и запись), затем сформированный буфер отсылал в дисплей (но он был не фрейм-буффером, а простым регистром данных с авто-инкрементом адреса внутри дисплейного контроллера. Читать память такого дисплея - дорогое удовольствие, к тому же всегда в формате пиксела 6:6:6,  что неудобно когда используеься 5:6:5)

Share this post


Link to post
Share on other sites
7 минут назад, __inline__ сказал:

На счёт чтения, не представляю себе пользы чтения видеопамяти дисплея.  Всегда заводил промежуточный буфер и делал там все операции - по альфа-смешению и прочее - в системной памяти (которая кеширована на чтение и запись), затем сформированный буфер отсылал в дисплей (но он был не фрейм-буффером, а простым регистром данных с авто-инкрементом адреса внутри дисплейного контроллера.

Может вам повезло, и аппаратный блиттер с возможностью копирования блоков, был документирован, но в аллвиннерах тут все печально. И ДМА в этом случае помошник не очень, медленный он, кэшированные облсти копируются процом в 3 раза быстрее...

Хотя есть и приятные моменты, все это дело, (ДМА, работа с памятью и копирование процом) на аллвиннерах работают куда лучше, чем в раскрученном IMX6...

Edited by mantech

Share this post


Link to post
Share on other sites
42 minutes ago, mantech said:

Может вам повезло, и аппаратный блиттер с возможностью копирования блоков, был документирован, но в аллвиннерах тут все печально. И ДМА в этом случае помошник не очень, медленный он, кэшированные облсти копируются процом в 3 раза быстрее...

Хотя есть и приятные моменты, все это дело, (ДМА, работа с памятью и копирование процом) на аллвиннерах работают куда лучше, чем в раскрученном IMX6...

 

Блиттера хардварного у меня не было. Всё делалось ручками (CPU).

 

Ещё по наблюдением, нужно было немного корректировать времянки дисплея в бОльшую сторону с использованием кеширования и DMA (параметры циклов записи на шину) - возможно из-за более плотной передачи данных. Пока не скорректировал - были артефакты на дисплее, вплоть до срыва всего кадра и отключения дисплея (интерфейс общения с дисплеем простой - через 2 порта: команда, данные).

 

На счёт медленности ДМА в оллвиннерах, может не всё так плохо? ДМА может хоть и медленее CPU перекидывает блок, но за счёт параллельности может давать выигрыш.

 

К примеру:

 

Программа идёт 9 мкс, отрисовка CPU 3 мкс - всего 12 мкс.

С ДМА:   программа - также 9 мкс, отрисовка ДМА: 9 мкс - в 3 раза медленее, но за счёт параллельности - суммарное время - 9 мкс вместо 12 мкс.

Тот самый случай когда за счёт параллельности достигается небольшой выигрыш, хотя ДМА меделенный.

 

На C6745 как-раз с этим сталкивался неоднократно - там встроенный сопроцессор PRUSS который намного слабже (частота вдвое ниже ядра, ограниченный набор команд, отсутствие кеша), чем сам DSP за счёт отрисовки параллельно давал нехилый суммарный выигрыш.

 

Edited by __inline__

Share this post


Link to post
Share on other sites
53 минуты назад, __inline__ сказал:

ДМА может хоть и медленее CPU перекидывает блок, но за счёт параллельности может давать выигрыш.

Так-то да, только 90% случаев все-равно приходится ждать, пока завершится транзакция, чтоб потом начинать следующую. Небольшой выигрыш был только в анимации, когда можно поставить отрисовку на "автомат" и уйти обратно в программу, а ДМА пусть "рисует". Сейчас это и оставил на откуп ДМА, да сохранять\восстанавливать основной фон, при открытии форм ГУЯ и закрытии их всех полностью, ибо в этом случае приходится перерисовывать экран в 2 слоя, что утомительно для проца..

58 минут назад, __inline__ сказал:

Пока не скорректировал - были артефакты на дисплее, вплоть до срыва всего кадра и отключения дисплея (интерфейс общения с дисплеем простой - через 2 порта: команда, данные).

У меня дисплей подключен к встроенному контроллеру, там все веселее с кэшем :dirol:

Share this post


Link to post
Share on other sites
2 часа назад, mantech сказал:

Так-то да, только 90% случаев все-равно приходится ждать, пока завершится транзакция, чтоб потом начинать следующую.

Плюс от использования DMA - не в увеличении скорости чего-то, а в уменьшении загрузки CPU. Когда освободившиеся такты CPU можно потратить на что-то более полезное, чем копирование байт из одного адреса в другой.

Share this post


Link to post
Share on other sites
54 минуты назад, jcxz сказал:

Плюс от использования DMA - не в увеличении скорости чего-то, а в уменьшении загрузки CPU.

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

Share this post


Link to post
Share on other sites
9 hours ago, mantech said:

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

 

Ради интереса поднял тесты на C6745. SDRAM 16 бит, 152 МГц. Кеширование включено. Передача буфера 128x128 коротких слов(2 байта на точку) разными порциями: байт, полу-слово, слово, двойное слово в дисплей (память закеширована, дисплей - нет):

 

#define LCD_BASE 0x60000000     /* 32MB Async Data (CS2) */

#define LCD_I  LCD_BASE
#define LCD_D (LCD_BASE+0x00004000) /* A12 */

#define LCD_I8 (*(volatile unsigned char*)LCD_I)
#define LCD_D8 (*(volatile unsigned char*)LCD_D)

#define LCD_I16 (*(volatile unsigned short int*)LCD_I)
#define LCD_D16 (*(volatile unsigned short int*)LCD_D)

#define LCD_I32 (*(volatile unsigned int*)LCD_I)
#define LCD_D32 (*(volatile unsigned int*)LCD_D)

#define LCD_I64 (*(volatile unsigned long long*)LCD_I)
#define LCD_D64 (*(volatile unsigned long long*)LCD_D)

 

//64 bit transfer: 128x128 651 FPS
 n>>=3;
 register u64 *P=(u64*)&Picture[o];
 while(n--)LCD_D64=*P++;

//32 bit transfer: 128x128 615 FPS
/*
 n>>=2;
 register u32 *P=(u32*)&Picture[o];
 while(n--)LCD_D32=*P++;
*/

//16 bit transfer: 128x128 553 FPS
/*
 n>>=1;
 register u16 *P=(u16*)&Picture[o];
 while(n--)LCD_D16=*P++;
*/

//8 bit transfer: 128x128 461 FPS
/*
 register u8 *P=(u8*)&Picture[o];
 while(n--)LCD_D8=*P++;
*/

 

С ДМА получилось чуть-больше, чем с 64-битной передачей :

 

//128x128 682 FPS
void EDMA3_Run(void)
{
 EDMA3_ESR=0x00000001;                   //Channel 0 set
}

 

Что важно, настройка DBS, меньше 32 байт даёт уже меньше производительность:

 L1P_Config(L1_SIZE_32K);         //Enable L1P L1D L2 Cache
 L1D_Config(L1_SIZE_32K);
 L2_Config(L2_SIZE_256K);

 SDRAM_Cacheable(CACHEABLE_ON);   //Enable SDRAM Cacheable

 CFGCHIP0=(2<<2)|2;               //PLL MMRs unlock & TC1 64 byte & TC0 64 byte (DBS)

 

В олвиннерах DBS регулируется?

 

В случае DDR сохраняется однотактность доступа к памяти через DMA? Может в этом кроется причина медленной работы DMA с DDR ?

 

В случае с C6745  SDRAM может работать в пакетном режиме - доступ вроде как однотактный там. Поэтому и DMA там довольно быстрый

Edited by __inline__

Share this post


Link to post
Share on other sites
17 часов назад, mantech сказал:

В том-то и дело, если такая нагрузка есть в данный момент. Если надо копировать N блоков, причем последовательно, и больше ничего в данный момент, кроме прерываний, на которые проц и так уйдет, когда будет вызов, то никакого выигрыша нет, скорей проигрыш, т.к. проц скопирует это быстрее.

Ну во-первых: в случае с прерываниями как раз и будет выигрыш, так как если копирует CPU, то "уйдёт в ISR" - значит перестанет копировать, а если DMA - продолжит.

Во-вторых: для описываемого случая (отрисовка в видеобуфере МК и отправка в видеопамять дисплея) частот как раз процессору всегда есть чем заняться. Так как часто бывает что закончив рисование очередного кадра, нужно как можно быстрее начать рисование следующего. Для всякой анимации - чем выше частота обновления - тем как правило лучше. И использование DMA в данном случае однозначно плюс.

17 часов назад, mantech сказал:

Возможно получить выигрыш при многозадачности

Да и в-3-их: на более-менее серьёзных МК работает как правило не одна задача одновременно. Так что CPU часто есть чем заняться.

Share this post


Link to post
Share on other sites
1 minute ago, jcxz said:

И использование DMA в данном случае однозначно плюс.

Вот уж не однозначно. 
Оконный движок может рисовать в том же буфере, который отправляет на дисплей. 
Причем перерисовывает не все, а только то что требует перерисовки, т.е. только изменения в картинке. 
И тогда одновременная работа DMA и программной перерисовки будет вызывать на экране неприятные артефакты. 
 

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