В этом апноуте обсуждается управление памятью кэша для семейства процессоров Blackfin® компании Analog Devices (перевод даташита EE-271 [1]). Представлены популярные схемы кэширования, и подробно рассматривается кэширование инструкций и кэширование данных. Описанные возможности доступны на всех моделях процессоров Blackfin. Вместе с этим апноутом предоставлены примеры кода [7], демонстрирующие управление кэшированием памяти. Примеры можно использовать для всех моделей процессоров семейства Blackfin.
Примечание: названия некоторых терминов для более ясного понимания смысла оставлены в тексте без перевода. Объяснение терминов технологии кэширования есть в разделе "Общая концепция кэширования -> Терминология кэша". Также незнакомые термины и сокращения см. в разделе Словарик этой статьи и статьи [2].
Рис. 1. Блок-диаграмма внутреннего устройства процессора ADSP-BF533.
Barrel Shifter, ASTAT, A1, A0, ... аппаратные узлы ядра, используемые в системе команд (узел сдвига на указанное количество бит за 1 такт, регистр состояния, аккумуляторы, ...).
CEC Core Event Controller.
DAG1, DAG0 Data Address Generator.
SIC System Interrupt Controller.
SD, LD0, LD1, RAB, DA0, DA1, IAB, IDB, PAB, DAB, DEB, EAB, EPB, DCB внутренние шины адреса и данных.
Scratchpad специальная память для временных данных.
SDRAM, ASYNC шины для подключения внешней памяти - динамической и асинхронной.
В этом разделе описываются общие принципы и терминология, применяемые в кэшировании кода и данных.
Конфигурация памяти. Системы, которые требуют большой объем памяти, обычно распределяют используемую память по нескольким уровням. Память самого верхнего уровня (аппаратно находящаяся ближе всего к ядру процессора, так называемая внутренняя память L1) предоставляет самый высокий уровень быстродействия, и эта память самая дорогая. Память более низких уровней требуют несколько циклов для доступа к ячейкам, но стоит дешевле (например, к такой памяти относится внешняя динамическая память SDRAM).
Память кэша - это специально выделенная контроллером кэша память высокого уровня (L1). Она защищена от прямого доступа как со стороны ядра, так и со стороны периферийных устройств. Применение контроллера кэша позволяет находиться секциям инструкций и данных находиться в памяти низкого уровня (обычно SDRAM), так что наиболее часто используемые данные и/или код (в зависимости от того, как сконфигурирован кэш) копируется в память кэша с помощью контроллера кэша. Достоверная копия в кэше работает намного быстрее, чем оригинальная медленная память (инструкции и данные доступны для выборки за 1 цикл ядра), поскольку это самая быстрая память L1. Архитектура кэша основана на принципе, что адресное пространство памяти делится на блоки фиксированного размера (которые в терминологии кэширования называются строками кэша). Строки кэша считаются самыми маленькими кусочками памяти, которые можно передать как копию из внешней (медленной) памяти во внутреннюю память кэша L1, если был зафиксирован промах кэша.
Обращение к памяти идентифицируется как ссылка на некий отдельный блок памяти. На рис. 2 показана конфигурация, в которой область внешней памяти поделена на 24 блока памяти, и память кэша поделена на 6 блоков (это пример основной конфигурации памяти. Количество блоков памяти может в действительности отличаться в зависимости от модели процессора Blackfin). Размер блока внешней памяти и блока памяти кэша одинаковый. Поскольку всегда память кэша по размеру состоит из 6 блоков (как в этом частном примере), то может быть только 6 блоков данных внешней памяти, которые будут доступны как кэшируемая копия.
Рис. 2. При кэшировании область памяти поделена на блоки фиксированного размера.
Терминология кэша
• Way, путь: массив строк хранилища в m-way кэше.
• Locked way, заблокированный путь: если way в состоянии locked (заблокирован), то он не участвует в политике обновления кэша "самый последний используемый" (least-recently used, LRU).
• Set, набор: группа областей хранения m-way в пути (way) кэша m-way. Отдельный блок памяти привязан к специфичному набору. Контроллер кэша выбирает way внутри набора set.
• Строка кэша, cache-line: 32-байтный непрерывный блок памяти который был передан как копия из/в память высокого уровня в/из кэша.
• Dirty/clean, грязная/чистая): состояние строки кэша, показывающая наличие или отсутствие расхождений оригинального значения во внешней памяти и соответствующей ему копии в строке кэша. Если различия есть, т. е. нет синхронности между кэшем и кэшируемой памятью, то строка грязная, если данные в оригинале или кэше не были поменяны, то строка чистая.
• Cache hit, попадание в кэш: процессор обрался к блоку памяти (находящемуся в основной, медленной памяти), которая уже имеет достоверную копию в кэше. В этом случае процессор сразу получит данные из кэша, с минимальной задержкой.
• Cache miss, промах кэша: процессор обратился к блоку памяти, который пока не доступен в кэше. Когда произошел промах кэша, контроллер кэша делает копирование блока в память кэша из низкоуровневой памяти.
• Victim, "жертва": грязная строка кэша должна быть записана в низкоуровневую память перед тем, как можно будет её освободить для записи в кэш новых данных (см. victim buffer на рис. 1).
Дополнительные подробности по терминологии кэширования можно получить из раздела "Memory" даташита "Blackfin Processor Programming Reference".
Примечание: в последующем изложении будут взаимозаменяемо использоваться слова line (строка), cache-line (строка кэша) и cache-block (блок кэша). Таким образом, блок внешней памяти представляет область такого же размера, как строка кэша.
[Размещение блока]
Используются 3 основные схемы во время принятия решения, где разместить приходящий блок в памяти кэша.
кэш с прямой привязкой (Direct Mapped Cache). В этой схеме каждый блок памяти низкого уровня имеет только один фиксированный блок назначения в кэше. Здесь присутствует привязка один-к-одному от низкоуровневой памяти к памяти кэша. Привязка основывается на адресе блока в памяти низкого уровня. Эта схема наиболее проста, и имеет самую низкую гибкость в использовании.
Полно-ассоциативный кэш (Fully Associative Cache). По этой схеме блок в основной (медленной) памяти может быть заменен на блок в памяти кэша. Привязка блоков полностью случайна. Эта стратегия имеет самую сложность в управлении, но предоставляет самую высокую гибкость в использовании.
Набор ассоциативного кэша (Set Associative Cache). Память кэша разбита на наборы. Набор (set) состоит из некоторого количества блоков. Любой блок в памяти низкого уровня имеет фиксированный набор назначения в кэше (куда он может быть помещен). Поступающий блок может заменить любые блоки внутри привязанного набора. Если в наборе есть m блоков, то конфигурация кэша называется m-way set associative. Этот метод размещения блока является компромиссным по сложности и гибкости. Рис. 3 показывает память 2-way set associate.
Рис. 3. Конфигурация памяти для 2-way set associative cache.
Первые 2 схемы являются специальными случаями set associative cache (direct mapped для m = 1, и fully associative для m = количеству строк кэша).
[Замена блока]
На рис. 4 показано сравнение замены блока для 1-way и 4-way set associative cache. Рассмотрим линейный поток через большой цикл в программе, расположенный во внешней памяти. Когда ячейки кэша были перезаписаны перед тем, как они могут использоваться, кэш считается "поврежденным". Более вероятно наличие требуемой инструкции для повторного использования в 4-way кэше, чем в 1-way кэше. Код должен использоваться повторно, чтобы получить преимущество в использовании кэша.
Рис. 4. Примеры размещения блока.
В кэше с прямой привязкой (direct mapped cache), всегда место внутри кэша фиксировано, в котором может быть помещена кэшируемая (внешняя) память. Однако, в размещении блока с полно-связанным кэшем (fully associative) или с набором связанного кэша (set-associative), может быть выбрано несколько мест при событии промаха кэша. Блоки, которые могут быть заменены, называются "участвующими" блоками. Вот некоторые стратегии, используемые чаще всего в выборе блока кэша для замены:
• Случайная замена: блок назначения выбирается случайно из участвующих блоков. Может использоваться генератор псевдослучайных чисел, чтобы выбрать блок назначения. Это самый простая, но наименее эффективная реализация. • Замена по принципу FIFO (First in first out, FIFO; принцип первым зашел, первым вышел): входящий блок заменяет самый старый из участвующих блоков. • Замена LRU (Least-recently used, LRU; последний используемый, т. е. используемый максимально давно): по этой схеме все доступы к блокам записываются. Будет выбран тот блок для замены, к которому не было последнего обращения самое длительное время. LRU полагается на местные условия использования: если только что использованные блоки скорее всего опять в ближайшее время понадобятся, то хорошим кандидатом для замены будет блок, который использовался максимально давно. • Модифицированный принцип замены LRU: "модифицированный" в случае процессора Blackfin означает, что бит 8 (CPLB_LRUPRIO) в регистрах данных CPLB установлен или очищен (см. рис. 17 и 18). У этого бита приоритет выше, чем у политики замены LRU. Согласно схеме модифицированного LRU, блоку присваивается низкий приоритет или высокий приоритет.
Если поступающий блок имеет низкий приоритет, то только блоки с низким приоритетом могут участвовать в замене кэша.
Если поступающий блок имеет высокий приоритет, то все низко-приоритетные блоки будут участвовать в замене кэша. Если нет низкоприоритетных блоков, то высокоприоритетные блоки могут участвовать в политике замены. Политика LRU используется для выбора блока-жертвы для замены среди участвующих блоков.
Не все блоки могут содержать в себе достоверную информацию. Например, в момент старта системы в кэше не содержится вообще никаких достоверных данных. Блоки кэша будут заполняться всякий раз, когда будут происходить обращения к внешней памяти с промахами мимо кэша. Механизм должен идентифицировать, содержится ли в блоке кэша достоверная информация. Чтобы проверить это, с каждым блоком кэша связывается так называемый бит достоверности, "valid" бит. Когда в кэше находятся достоверные данные, совпадающие с соответствующим блоком внешней памяти, то valid-бит для этого блока кэша установлен.
В дополнение к valid-биту, каждый блок в кэше также имеет привязанный к нему тэг адреса. Этот адрес предоставляет физический адрес кэшируемого блока во внешней памяти. Когда происходит обращение к блоку внешней памяти, контроллер кэша сравнивает внешний адрес с тэгами адреса кэша (у блоков, которые имеют установленным valid-бит), чтобы найти набор данных, который может содержать этот блок. Если адрес блока совпадает с одним из тегов адреса кэша, то происходит попадание в кэш (т. е. в кэше найдена информация, соответствующая запрашиваемому блоку из внешней памяти).
В конфигурации set-associative cache каждый адрес памяти может рассматриваться как комбинация трех полей (см. таблицу 1). Первое деление происходит между адресом блока и смещением блока. После этого адрес блока (фрейм) может быть также поделен на поле тэга и поле индекса.
Таблица 1. Разбиение адреса.
Адрес блока
Смещение блока
Поле тэга
Поле индекса
Используется контроллером кэша, чтобы определить попадание или промах кэша
Используется для привязки указанного блока к определенному набору (set)
Используется для выбора слова в пределах указанного блока
Поле смещения блока выбирает нужные данные из блока. Поле индекса выбирает набор, и поле тэга сравнивается с этим, чтобы определить попадание в кэш.
[Стратегия записи]
Здесь рассматриваются две разные проблемы, возникающие при операции записи в память, связанной с данными кэша.
Операция записи в случае попадания в кэш. Здесь имеется 2 основные опции при записи данных обратно во внешнюю память:
• Write-through (WT), сквозная запись: информация записывается как в блок кэша, так и в блок оригинальной внешней памяти, соответствующей блоку кэша. Поведение/скорость работы этой схемы подобны простой записи во внешнюю память, когда кэш не используется.
• Write-back (WB), обратная запись: информация записывается только в блок кэша. При модификации измененная строка кэша (victim cache-line) записывается во внешнюю память только когда этот блок кэша заменяется.
Примечание: операция сохранения (store), особенно в режиме работы WT, будет обновлять только модифицированные данные. Не будет осуществляться целой строки кэша во внешнюю память, если это не требуется.
Чтобы уменьшить частоту обратной записи блоков при замене, обычно используется фича, называемая "грязный бит", dirty-бит. Это бит состояния, показывающий грязный блок в кэше или нет (под "грязным" блоком подразумевается модифицированный блок; если блок кэша не был модифицирован, то он считается "чистым"). Чистый блок не будет записан обратно при замене этого блока. Хотя многое зависит от приложения, но режим WB работает эффективнее примерно на 10..15%, чем режим WT. Режим WT лучше использовать, когда должна поддерживаться когерентность между двумя или большим количеством ресурсов (например, DMA и ядро).
Операции записи с промахами кэша. Поскольку данные не были необходимы при записи, здесь есть две опции при промахе кэша на записи:
• Write allocate, выделение блока при записи: при промахе кэша выделяется блок, за которым происходят действия, как при попадании в кэш, описанные выше. По такой схеме промах мимо кэша при записи работает так же, как промах мимо кэша при чтении. Сначала строка кэша захватывается из внешней памяти, перед тем как обновить как внутренний кэш, так и внешнюю память. • No-write allocate, без выделения блока при записи: при этой схеме промахи кэша при записи никак не влияют на содержимое кэша. Блок будет модифицирован только во внешней низкоуровневой (медленной) памяти, и не будет кэшироваться.
[Модель кэша, используемая процессором Blackfin]
У процессоров Blackfin есть до 3 уровней иерархии памяти - L1, L2, L3 - чтобы предоставить некий компромисс между объемом памяти и быстродействием (память L2 есть только у двухядерного ADSP-BF561). Память L1 предоставляет самое высокое быстродействие при самой малой емкости. Типы памяти L2 и L3 предоставляют объемы больше, чем L1, однако для доступа к ним обычно требуется несколько тактов.
У процессоров Blackfin есть банки памяти L1 данных и инструкций, которые можно независимо конфигурировать как SRAM или как кэш. Когда память сконфигурирована как кэш, то к ней не имеют прямого доступа ни контроллер DMA, ни инструкции загрузки/сохранения ядра. У всех процессоров Blackfin конфигурация кэша происходит почти одинаково (см. таблицу 2), но последующее описание будет основана на примере конфигурирования процессоров ADSP-BF533.
Примечание: внутренняя память L1 процессора Blackfin подключена через шину External Access Bus (EAB) к блоку внешней шины External Bus Interface Unit (EBIU), который обрабатывает доступы к внешней памяти (например к памяти SDRAM). Любая текущая активность EAB не может быть прервана, начатое заполнение строки кэша обязательно закончится.
Таблица 2. Карта памяти процессоров Blackfin.
[Конфигурирование кэша инструкций Blackfin]
Организация кэша. У процессора ADSP-BF533 имеется 80 килобайт встроенной в кристалл памяти инструкций. 64 килобайта памяти инструкций доступны как SRAM инструкций. Остальные 16 килобайт памяти можно сконфигурировать как кэш инструкций, либо можно их использовать как SRAM инструкций. В таблице 2 показана комбинированная карта памяти для всех доступных в настоящее время процессоров семейства Blackfin.
У всех моделей процессоров Blackfin предоставляется одинаковое количество памяти инструкций, которое можно сконфигурировать либо как кэш инструкций, либо как SRAM. Начальный адрес в карте памяти всегда одинаковый.
Когда эта память разрешена для кэша, память инструкций работает как 4-way set associative memory. Каждый из 4 путей можно заблокировать независимо. Контроллер кэша инструкций можно сконфигурировать для использования модифицированной политики LRU (см. врезку "Общая концепция кэширования"), или простую политику LRU для принятия решения по замене строки кэша.
• 16 килобайтный кэш организован как 4 подбанка по 4 килобайта каждый. Подбанк выбирается битами адреса памяти [13:12]. • Каждый 4 килобайтный подбанк состоит из 32 наборов. Набор выбирается битами адреса памяти [9:5]. • Каждый набор состоит из 4 путей (way). Путь выбирается контроллером кэша в соответствии с политикой размещения строки кэша. Пути можно идентифицировать битами адреса [11:10] в SRAM. • Другими словами, набор 0 (set-0) представляет четыре пути для строки 0 (line-0). • Размер строки кэша (для чтения в случае промаха кэша) равен 32 байта.
Внешний порт чтения данных (для контроллера кэша) имеет ширину 64 бита (8 байт). Следовательно, контроллер кэша читает всю строку кэша как пачку из четырех 8-байтных кусков данных.
У каждой строки есть тэг, связанный с ней. Тэг состоит из следующих 4 частей:
• 20-битный тег адреса: сравнивается с адресом памяти, чтобы определить попадание в кэш или промах кэша. • LRU Priority: приоритет для модифицированной политики LRU. • LRU State: состояние LRU, используется контроллером кэша для обработки политики LRU. • Valid-бит: показывает достоверность данных строки.
32-битная область адреса привязана к области памяти кэша следующим образом:
• Выбор подбанка (Subbank Select): выбирается отдельный 4 килобайтный подбанк. • Выбор набора (Set Select): выбирается набор из 32 наборов кэша. • Выбор байта (Byte Select): выбирается байт из данной строки.
На рис. 5 показано, как организован 4 килобайтный подбанк кэша инструкций. Каждый 4 килобайтный подбанки имеет одинаковую структуру.
Рис. 5. Конфигурация кэша инструкций для одного подбанка, применена организация кэша 4-way set associative.
Таблица 3. Политика замены для кэша инструкций Blackfin.
Ситуация
Стратегия
Только один недостоверный way в наборе (set)
Приходящий блок заменит этот блок
Больше одного недостоверного way в кэше
Недостоверный way будет заменен в таком порядке: первым way0, затем way1, way2, и в конце way3.
В кэше нет недостоверных way
Будет заменен используемый максимально давно way (Last-recently used, LRU). Для модифицированной политики LRU: way с высоким приоритетом не будет заменен, если имеется в этом наборе way с низким приоритетом. Низкоприоритетный блок не может заменить высокоприоритетный. Если у всех way высокий приоритет, то way с низким приоритетом не может кэшироваться.
Попадания/промахи кэша и замена строки кэша. Попадание в кэш определяется путем сравнения старших 18 бит и битов 11 и 10 адреса выборки инструкции с тегом адреса достоверных строк, находящихся в данный момент в наборе кэша. Если сравнение с тегом адреса показывает совпадение, то получается попадание в кэш. Если сравнение не дало положительного результата, то получается промах мимо кэша.
Предположим, что произошел доступ по адресу 0x10374956. Этот адрес привязан к set-10 подбанка 0. Старшие 18 бит и биты 11-10 этого адреса (формируют слово тэга) будут сравниваться со всеми достоверными тэгами (у которых установлен valid-бит) в наборе set-10.
При промахе кэша блок памяти инструкций генерирует доступ на заполнение строки кэша, чтобы получить недостающую строку кэша из внешней памяти. Ядро приостанавливает работу, пока не будет возвращено целевое слово инструкции из внешней памяти.
Адрес для доступа к внешней памяти является адресом целевого слова инструкции. Блок замены строки кэша использует биты Valid и LRU (на разблокированных путях, unlocked ways), чтобы определить, какой блок (из имеющихся блоков в наборе) будет использоваться для новой строки кэша. В таблице 3 показано, как выбирается политика замены строки кэша.
Заполнение строки кэша состоит из захвата 32 байт (один блок) данных из памяти. Адрес для передачи чтения является адресом целевого слова инструкции. При ответе на запрос чтения строки от блока инструкций памяти внешняя память вернет сначала 64-битное слово целевой инструкции. Следующие 3 слова будут захватываться друг за другом в последовательных адресах, как это показано в таблице 4.
Таблица 4. Порядок выборки слова строки кэша инструкций.
Целевое слово
Порядок выборки для следующих трех слов
WD0
WD0, WD1, WD2, WD3
WD1
WD1, WD2, WD3, WD0
WD2
WD2, WD3, WD0, WD1
WD3
WD3, WD0, WD1, WD2
Когда блок кэша выбирается из внешней памяти, каждое 64-битное слово буферизируется в 4-ячеечном буфере заполнения строки, перед тем как оно будет записано в 4 килобайтный банк памяти. Буфер заполнения строки позволяет ядру получить данные из новой строки кэша во время, когда строка передается из внешней памяти, без ожидания, пока вся строка будет записана в кэш.
• кэш выключен: делается выборка 64 бит / 8 байт • кэш включен: всегда делается выборка 256 бит / 32 байт (ускоренное пакетное заполнение) • Поскольку интерфейс к SDRAM (внешняя память) на большинстве процессоров Blackfin имеет ширину 16 бит, то каждая выборка инструкции состоит из последовательности 16-битных доступов к памяти.
На рис. 6 показана выборка инструкции из внешней памяти SDRAM (целевой адрес 0x000Ah), когда кэш инструкций выключен. При этом выбирается 64-битный блок (определен как WDx). Начальный адрес блока 0x0008h, поскольку доступ (выборка инструкции) выровнен на границу в 64 бита.
Рис. 7 показывает тот же самый доступ, когда кэш инструкций включен. Начальный адрес остался равным 0x0008h. Это начало WD1. WD2 начинается с адреса 0x0010h, и WD3 начинается с адреса 0x0018h. WD0 с адресом 0x0000h является последней частью передаваемого блока кэша.
Рис. 8 и 9 показывают задержки выполнения для инструкций, сохраненных во внешней памяти (начальный адрес 0x00000). Сигнал "GPIO" переключится из 1 в 0 функцией, расположенной в внешней памяти. Эта функция будет выглядеть примерно так, как на этом листинге:
Для доступа к памяти SDRAM выполняется несколько операций при фактическом чтении памяти (RD: означает команду чтения). Подробнее про быстродействие SDRAM см. раздел "Соображения производительности".
Рис. 8 и 9 показывают доступ к специфичному банку в памяти SDRAM. Сначала целевая строка (row, имеется в виду не строка кэша, а строка SDRAM) должна быть открыта в отдельном банке (ACT: команда Active).
После задержки ACTIVE-to-READ-or-WRITE (tRCD, здесь это 3 такта SCLK), может быть отправлена команда чтения. После задержки выставления сигнала столбца CAS (CL, здесь это 3 такта SCLK), становится доступной первая порция данных.
До настоящего момента задержка доступа с включенным кэшем и с выключенным кэшем пока одинаковая. Для первого 64-битного блока инструкций нет никаких отличий, время выполнения одинаковое. После примерно 10 тактов SCLK выполняется первая инструкция.
Достоинство кэша инструкций проявляется для следующей порции кода – и обычно процесс выполнения программы линеен – который вычитывается после первого 64-битного блока. В сравнении со строкой кэша в 256 бит, это займет около 4x11 (плюс ACT) тактов SCLK, пока последняя порция данных не будет доступна на EAB, когда кэш инструкций не разрешен.
Когда кэш инструкций разрешен, та же самая операция выполнится за 21 такт SCLK (включая ACT).
Рис. 6. Выборка инструкции, когда кэш отключен.
Рис. 7. Выборка инструкции, когда кэш включен.
Рис. 8. Задержка с инструкцией, когда кэш отключен.
Рис. 9. Задержка с инструкцией, когда кэш включен.
[Конфигурирование кэша данных Blackfin]
Организация кэша. У процессора ADSP-BF533 имеется 64 килобайта встроенной в кристалл памяти данных. 32 килобайта памяти данных доступны как SRAM данных. Остальная часть - еще 32 килобайта памяти - доступна как 2 независимых банка памяти по 16 килобайт, которые можно конфигурировать либо как кэш данных, либо как SRAM данных.
Некоторые модели семейства процессоров Blackfin предоставляют только один банк памяти данных, который можно сконфигурировать либо как кэш данных, либо как SRAM. Подробности см. в таблице 2.
Когда кэш данных разрешен, то он работает как память 2-way set associative. Контроллер кэша данных использует политику LRU для замены строки кэша (он не может использовать модифицированную политику LRU, как это имеет место с кэшем инструкций).
• В зависимости от количества банков, сконфигурированных как кэш, кэш данных может занимать либо 16 килобайт (один банк), либо 32 килобайта (два банка). • Каждый 16 килобайтный банк кэша данных организован как четыре 4-килобайтных побанка. Подбанк выбирается по битам адреса памяти [13:12]. • Каждый 4-килобайтный подбанк состоит из 64 наборов (set). Набор выбирается битами адреса памяти [10:5]. • Каждый набор состоит из 2 путей (way). Путь выбирается контроллером кэша в соответствии с политикой размещения строки кэша. Пути можно идентифицировать по биту адреса [11] в SRAM. • Другими словами, набор set-0 представлен двумя путями строки line-0. • Размер строки кэша (которая подлежит чтению при промахе мимо кэша) составляет 32 байта.
Подобно кэшу инструкции, каждая строка кэша имеет связанную с ней порцию тега (см. рис. 10):
• 19-битный тег адреса: сравнивается с адресом памяти, чтобы определить попадание в кэш или промах мимо кэша. • Dirty-бит: этот бит показывает, что строка кэша была модифицирована. • LRU state: используется контроллером кэша для реализации политики LRU. • Valid-бит: показывает достоверность данных строки кэша.
32-битное адресное пространство привязано к памяти кэша следующим образом (см. рис. 10):
• Subbank select (выбор подбанка): выбирает отдельный 4-килобайтный подбанк. • Set select (выбор набора): выбирает набор (set) из 64 наборов кэша. • Byte select (выбор байта): выбирает байт из имеющейся строки.
На рис. 10 показано, как организован 4-килобайнтный подбанк кэша данных. Когда оба банка данных разрешены для кэша, то в зависимости от состояния бита DCBS либо бит 14 (каждые 16 килобайт) или бит 23 (каждые 8 мегабайт) адресного пространства используется для выбора одного из 16-килобайтных банков данных (см. рис. 11).
Доступ на заполнение строки кэша состоит из захвата 32 байт данных из памяти. Адрес для трансфера чтения это адрес целевого слова данных. Предположим, что имел место доступ I/O на чтение 16-битной памяти, когда происходит ответ на запрос чтения строки от блока чтения памяти, внешняя память возвратит сначала 16-битное целевое слово данных. Следующие 15 слов будут захвачены друг за другом в последовательных адресах, как показано в таблице 5.
Таблица 5. Порядок выборки слова строки кэша данных.
Целевое слово
Порядок выборки для следующих 15 слов
WD0
WD0, ..., WD15
WD1
WD1, ..., WD15, WD0
WD2
WD2, ..., WD15, WD0, WD1
WD15
WD15, WD0, ..., WD14
Когда строка кэша забирается из внешней памяти, каждое 32-битное слово буферизуется в 8-ячеечном буфере заполнения строки (line fill buffer), перед записью в 4-килобайтный банк памяти. Буфер заполнения строки позволяет ядру получить доступ к данным из новой строки кэша как к строке, получаемой из внешней памяти, без ожидания, пока строка будет записана в кэш.
В отличие от инструкций, данные обычно модифицируются и записываются обратно во (внешнюю) память. Любая кэшируемая одиночная (не пакетная) запись ядра во внешнюю память происходит через буфер записи. Глубина этого буфера может изменяться в соответствии с настройками в регистре приоритета прерываний (interrupt priority register, IPRIO).
Третий буфер используется для чтения грязной строки кэша, которая сбрасывается (flush) или заменяется заполнением строки кэша и затем для инициализации пакетной операции записи на шине, чтобы выполнить обратное копирование строки во внешнюю память. Этот буфер называется "буфером жертвы", victim-буфер. Он реализован наподобие буфера заполнения строки, как FIFO глубиной 8 ячеек, у каждой ширина 32 бита (см. рис. 1).
Рис. 10. Конфигурация кэша данных для одного подбанка – 2-way set associative.
Рис. 11. Привязка кэша данных в соответствии с битом DCBS.
Рис. 12. Выборка данных, когда кэш выключена.
Рис. 13. Выборка данных, когда кэш включена.
Выборка данных из внешней памяти
• кэш выключена: доступ шириной 1 байт, 2 байта или 4 байта • кэш включена: всегда делается выборка 256 бит / 32 байта (пакетное ускоренное заполнение) • Поскольку интерфейс SDRAM на большинстве процессоров Blackfin 16-битный, то каждый доступ будет шириной 16 бит. При доступе к байту младший или старший байт маскируется сигналом SDQM.
Рис. 12 показывает доступ к внешней памяти на чтение 16-битных данных (целевой адрес 0x0032h). кэш данных выключен. Для каждого доступа выбирается одно 16-битное слово.
Рис. 13 показывает тот же самый доступ, но с включенным кэшем данных. Здесь начальный адрес 0x0032h. Другие данные, принадлежащие этой кэшируемой строке будут выбраны так, как показано в таблице 5.
Методы записи кэша. Внешняя память поделена на разные страницы (определенные через регистры защиты буферов данных кэша - data cache protection lookaside buffers, регистры DCPLB). Атрибуты для каждой страницы можно конфигурировать независимо. Как будет показано в следующей секции, страницы памяти могут быть:
• Сконфигурированы либо в режиме записи write-back WB, либо в режиме записи write-through WT (бит CPLB_WT). • Сконфигурированы для выделения строк кэша либо только для чтения, либо для чтения и записи (бит CPLB_L1_AOW).
Таблица 6. Поведение в специфической ситуации записи.
Строка кэша достоверная (valid)
Строка кэша недостоверная (invalid)
WT AOW=0
Обновление строки кэша и внешней памяти
Обновление только внешней памяти
WT AOW=1
Обновление строки кэша и внешней памяти
Выборка строки кэша Обновление строки кэша Обновление внешней памяти
WB
Обновление только строки кэша
Выборка строки кэша Обновление строки кэша
Таблица 6 показывает поведение в различных методах записи кэша. Рис. 14 показывает ситуацию, когда кэш данных разрешен в режиме write-through (WT), и с установленным битом CPLB_L1_AOW. Инициируется доступ на запись по адресу 0x0040h. Сначала выполняется заполнение строки кэша, затем происходит запись во внешнюю память.
Рис. 14. Выборка данных с включенным кэшем, когда включен режим записи write-through и разрешен AOW.
Блок защиты памяти и кэша (Memory Protection and Cache Unit). Процессор Blackfin содержит основанный на страницах блок защиты памяти Memory Protection and Cache Unit (MPCU), который предоставляет контроль над кэшированием диапазонов памяти и управление атрибутами защиты на уровне страницы. MPCU реализован как блоки 16-ячеечной, адресуемой по содержимому памяти (content addressable memory, CAM). Каждая ячейка называется дескриптором cacheability protection lookaside buffer (CPLB). Функционал MPCU включает:
• Буферы кэширования и защиты (Caching and protection lookaside buffers, CPLB) • Свойства кэша/защиты, определяемые на базе страницы памяти (размерами 1 килобайт, 4 килобайта, 1 мегабайт и 4 мегабайта) • Защита доступа режимов User/supervisor, и защита задача/задача
Защита буферов кэша (Cacheability Protection Lookaside Buffers, CPLB). Каждая запись в дескрипторах CPLB задает атрибуты кэшируемости и защиты для определенной страницы памяти. Записи CPLB поделены между CPLB инструкций и данных. 16 записей CPLB (называемых ICPLB) используются для запросов выборки инструкции. Другие 16 записей CPLB (называемых DCPLB) используются для транзакций данных. Установка соответствующих бит в регистрах управления памятью инструкций (IMEM_CONTROL) и регистрах управления памятью данных (DMEM_CONTROL) разрешают работу ICPLB и DCPLB. Каждая запись CPLB состоит из пары 32-битных значений. Перед загрузкой данных дескриптора в любой CPLB соответствующая группа из 16 CPLB должна быть запрещена с использованием битов ENICPLB или ENDCPLB в регистре IMEM_CONTROL или DMEM_CONTROL соответственно.
Для выборок инструкций: ICPLB_ADDR[n] задает начальный адрес страницы, описанной дескриптором CPLB. ICPLB_DATA[n] определяет свойства страницы, описанной дескриптором CPLB. На рис. 15 показаны различные битовые поля в регистре ICPLB_DATA и их функциональность.
Для операций с данными: DCPLB_ADDR[m] задает начальный адрес страницы, описанной дескриптором CPLB. DCPLB_DATA[m] определяет свойства страницы, описанной дескриптором CPLB. Рис. 16 показывает различные битовые поля в регистре DCPLB_DATA и их функциональность.
Использование CPLB
• Если кэш разрешена: CPLB должны использоваться для определения свойств кэша. • Если кэш запрещена: CPLB могут использоваться для защиты страниц памяти. • Если CPLB используются, то должна существовать правильно настроенная запись CPLB до того, как будет сделана попытка доступа к определенной области памяти. Иначе будет сгенерировано исключение. • Есть два дескриптора CPLB по умолчанию - для памяти данных scratchpad и для пространства адресов MMR системы и ядра. Эти дескрипторы по умолчанию определяют вышеуказанные области как не кэшируемые, так что не нужны дополнительные CPLB для настройки этих регионов памяти.
Примечание: если для этой области настроены правильные CPLB, то CPLB по умолчанию будут игнорированы. На новых членах семейства Blackfin, таких как ADSP-BF51x, ADSP-BF52x и ADSP-BF54x, встроенная в кристалл память программ boot ROM (память только для чтения) предоставляет функции (SysControl()) для доступа к регистрам PLL и регистрам регулятора напряжения. Также дополнительно доступны внутренние L1 ROM инструкций и/или L2 SRAM. Для всех этих случаев требуется правильно настроенный дескриптор CPLB (инструкций и данных). См. даташит на процессор или таблицу 2 для подробностей о том, какое количество памяти имеется в определенного процессора семейства Blackfin.
Рис. 15. Битовые поля и их функциональное назначение для регистров ICPLB_DATA.
Рис. 16. Битовые поля и их функциональное назначение для регистров DCPLB_DATA.
[Страницы памяти и атрибуты страницы]
Каждая запись CPLB соответствует допустимой странице памяти. Каждый адрес в пределах страницы использует одни и те же общие атрибуты, заданные для этой страницы. Дескриптор адреса xCPLB_ADDR[n] предоставляет базовый адрес положения страницы в памяти. Слово свойств дескриптора xCPLB_DATA[n] задает размер и атрибуты для этой страницы. Рис. 15 и рис. 16 показывают различные битовые поля и их функциональность в регистрах ICPLB_DATAx и DCPLB_DATAx соответственно. Ниже дано короткое описание полей бит.
Page Size (размер страницы). Архитектура памяти Blackfin поддерживает 4 различные размера страницы: 1 килобайт, 4 килобайт, 1 мегабайт или 4 мегабайта. Страницы должны быть выровнены по границам страниц, адрес которых должен нацело делиться на размер страницы.
Cache-Line Allocation (выделение строки кэша). Разрешена кэш типа write-through, что представлено только для памяти данных. Бит CPLB_L1_AOW определяет, инициировано ли заполнение строки кэша только для чтения или также и для записи. Для записей, с которыми бит CPLB_L1_AOW не устанавливается, кэш ведет себя так, как будто её нет. Если этот бит установлен, то заполнение кэша срабатывает после чего идет обновление внутренней или внешней памяти.
Write-Through/Write-Back Flag (флаг типа кэша). Этот флаг представлен только для памяти данных. Он соответствует атрибуту (бит CPLB_WT), разрешающему режим write-through для данных, когда бит установлен. По умолчанию (CPLB_WT = 0) активен режим write-back.
Cacheable/Non-cacheable Flag (флаг кэшировать/не кэшировать). Если страница определена как не кэшируемая (CPLB_L1_CHBL = 0), то при доступе к этой странице кэш не используется. Страницы памяти могут быть на определены как кэшируемые, когда:
• Устройство ввода/вывода (I/O) отображено на адрес памяти. • Код, находящийся в этой странице, вызывается нечасто (пользователь может не желать его кэшировать). • Код программы экстремально нелинейный.
LRU Priority (приоритет LRU). Этот атрибут (CPLB_LRUPRIO) доступен только для CPLB памяти инструкций. Он определяет приоритет LRU (low/high, низкий/высокий) для указанной страницы. Это используется для модифицированной политики LRU (см. разделы "Размещение блока", "Замена блока").
Dirty/Modified Flag (флаг актуального состояния модифицированности кэша). Бит CPLB_DIRTY дает программисту выбор для сигнализации о том, что произошел (первый) доступ на запись во внешнюю память. Представленный только для памяти данных, этот атрибут достоверен только когда страница определена как кэшируемая в режиме write-back. Этот бит должен быть установлен программно для сохранения доступов к этой странице. Когда этот бит очищен, тио доступ к этой странице вызывает исключение (EXCAUSE 0x23). Обработчик исключения должен устанавливать этот бит, чтобы пометить страницу как грязную.
Write Access Permission Flags (флаги разрешения на модификацию памяти). CPLB для памяти данных имеют 2 флага, которые разрешают/запрещают доступ на запись в соответствующую страницу индивидуально для режима супервизора (CPLB_SUPV_WR) и для режима пользователя (CPLB_USER_WR).
User Read Access Permission Flag (флаг разрешения доступа на чтение для режима пользователя). Этот атрибут (CPLB_USER_RD) разрешает/запрещает чтения этой страницы кодом, работающем в user mode.
Lock Flag (флаг блокировки). Когда бит CPLB_LOCK, соответствующая запись CPLB заблокирована. Этот атрибут полезен для управления динамической памятью. Когда запись CPLB заблокирована, обработчик исключения промаха CPLB не рассматривает этот блок для замены.
Атрибуты страницы, связанные с разрешением чтения/записи позволяют реализовать защиту памяти. Это может потребоваться для приложений реального времени, в которых все приложение разделено на код пользователя и код операционной системы. Код пользователя может иметь несколько разных потоков, причем каждый поток имеет собственные ресурсы памяти, которые недоступны для других потоков. Однако ядро операционной системы может получить доступ ко всем ресурсам памяти. Эта задача может быть решена настройкой разных конфигураций CPLB в разных потоках.
Когда CPLB разрешены, должна существовать допустимая запись CPLB а таблице CPLB для каждого адреса, в который делается доступ. Если нет допустимых записей для страниц, к которым произошло обращение, то генерируется исключение CPLB.
[Регистры состояния CPLB (CPLB Status Registers)]
MPCU имеет 2 независимых регистра состояния: один для статуса ICPLB (рис. 17), и один для статуса DCPLB (рис. 18).
FAULT_ILLADDR. Произошла попытка записи в память, которая не существует. FAULT_DAG. Этот бит показывает, что DAG0 или DAG1 привел к неправильному доступу к данным (только DCPLB). FAULT_USERSUPV. Доступ был сделан либо в режиме пользователя (user mode), либо в режиме супервизора (supervisor mode). FAULT_RW. Доступ к данным был либо на чтение, либо на запись (только DCPLB). FAULT. Состояние попадания/промаха (hit/miss) связанной записи CPLB.
Рис. 17. Битовые поля и их функциональность для регистра состояния ICPLB.
Рис. 18. Битовые поля и их функциональность для регистра состояния DCPLB.
Table 7. События CPLB, которые вызывают исключения [6].
Исключение (Exception)
EXCAUSE [5:0]
Примечания/примеры
Нарушение защиты доступа CPLB к данным
0x23
Сделана попытка доступа к ресурсу супервизора (см. [6]), либо недопустимый доступ к памяти. Эта запись используется для сигнализации о нарушении защиты, к которому привел не разрешенный доступ к памяти, и это задано блоком MPCU и CPLB.
Нарушение доступа к данным, связанное с невыровненным адресом
0x24
Была попытка невыровненного доступа к данным памяти или данным кэша.
Промах CPLB при доступе к данным
0x26
Используется MPCU для сигнализации о промахе CPLB при доступе к данным.
Множественное попадание CPLB при доступе к данным
0x27
Адресу выборки данных соответствует больше одной записи CPLB.
Нарушение защиты CPLB при выборке инструкции
0x2B
Недопустимый доступ выборки инструкции (нарушение защиты памяти).
Промах CPLB при выборке инструкции
0x2C
Промах CPLB при выборке инструкции программы.
Множественное попадание CPLB при выборке инструкции
0x2D
Адресу выборки инструкции соответствует больше одной записи CPLB.
[Исключения секвенсора, связанные с CPLB]
В регистрах ICPLB_DATAx и DCPLB_DATAx некоторые политики доступа (чтение/запись в user mode и supervisor mode) могут быть заданы для определенных областей памяти. Нарушение правил доступа приводит к исключениям секвенсора.
Причиной исключения может быть чтение из поля бит EXCAUSE регистра состояния секвенсора (sequencer status register, SEQSTAT). В таблице 7 показан список всех исключений, которые могут поступать от CPLB.
Обычно основанная на памяти структура для управления CPLB называется page descriptor table (таблица дескрипторов страниц, PDT). Все потенциально необходимые записи CPLB могут быть сохранены в PDT (которая обычно находится во внутренней памяти SRAM). Когда нужно сконфигурировать CPLB, код приложения может взять записи CPLB из PDT и заполнить их в регистры дескриптора CPLB.
Для малой/простой модели памяти иногда можно определить набор дескрипторов CPLB, который поместится в 32 записи CPLB (16 ICPLB и 16 DCPLB). Этот тип определения называется как статическая модель управления памяти. Пример Example1 (1) использует статическую модель управления памяти.
Для сложных моделей памяти в PDT могут быть записи CPLB, которые не укладываются в доступные 16 регистров CPLB. Для этих условий CPLB может быть сконфигурирован сначала с этими любыми 16 записями. Когда процессор обращается к определенному месту в памяти, которая не определена через записи CPLB, генерируется исключение, и адрес вызвавшей ошибку памяти сохраняется в регистр ошибки адреса (Fault Address register, xCPLB_FAULT_ADDR). Обработчик исключения может использовать этот адрес для поиска нужной записи CPLB в PDT. Одна из существующих записей CPLB может быть заменена этой новой найденной записью CPLB, взятой из PDT.
Политика замена CPLB может быть простой или сложной, в зависимости от требований системы. Может произойти так, что больше чем одно обращение к памяти, для которой нет записи в дескрипторах. В таких условиях исключения приоритезируются и обрабатываются в следующем порядке:
1. Промахи страницы для инструкций. 2. Промахи страницы на DAG0. 3. Промахи страницы на DAG1.
Пример кода в Example2 (2) предоставляет обработчик исключений для промахов DCPLB (см. таблицу 7: EXCAUSE 0x26). Он использует карусельный метод шедулинга (round-robin) для замены DCPLB.
[Соображения, касающиеся когерентности кэша]
Если внешний источник (например контроллер DMA) обращается к внешней памяти, которая определена как кэшируемая, программист должен гарантировать когерентность памяти. Контроллер кэша не знает ни о каких изменениях, которые были сделаны не процессором. Простой опрос памяти работать не будет.
Пример для такой ситуации - кольцевой буфер, который хранится во внешней памяти. Данные передаются между этим буфером и периферийным интерфейсом (например, какой-то поток аудиоданных). Ядро должно сделать некоторые вычисления и записать данные обратно в буфер, откуда данные передаются обратно в периферийный интерфейс. В этом случае желательно использовать стратегию write-through (сквозная запись). В таблице 8 показаны стадии конвейера инструкций процессора Blackfin.
Таблица 8. Стадии конвейера инструкций.
Instr Fetch 1 (выборка инструкции 1)
Instr Fetch 2 (выборка инструкции 2)
Instr Fetch 3 (выборка инструкции 3)
Instr Dec (декодирование инструкции)
Addr Calc (вычисление адреса)
Data Fetch 1 (выборка данных 1)
Data Fetch 2 (выборка данных 2)
Ex 1
Ex 2
Write-Back
На стадии 1 (IF1) адрес инструкции выдается на шину доступа к инструкции (Instruction Access Bus, IAB). В этой фазе запускается сравнение тэгов кэша инструкции.
На стадии 6 (DF1) адрес данных выдается на шину доступа к данным (Data Access Buses, DA0 и DA1). В этой фазе запускается сравнение тэгов кэша данных.
Подробнее про конвейер инструкций см. раздел "Program Sequencer" в руководстве программирования процессора Blackfin [3].
[Обработка кэша инструкции и данных]
Разрешение кэша. кэши инструкции и данных могут быть разрешены или запрещены независимо друг от друга путем конфигурирования регистров IMEM_CONTROL и DMEM_CONTROL соответственно. Пример демонстрирует, как можно разрешить кэши данных/инструкции:
• Перед тем, как разрешить кэш, должны быть настроены и разрешены корректные дескрипторы CPLB. • Когда память сконфигурирована как кэш, к ней нельзя получить доступ напрямую (ни со стороны ядра, ни через DMA).
Instruction Memory Control Register (IMEM_CONTROL). Рис. 19 показывает различные битовые поля и их функционал регистра управления памятью инструкций IMEM_CONTROL.
LRU Priority Reset (сброс приоритета LRU). Бит LRUPRIORST может использоваться для сброса всех битов приоритета кэширования LRU.
Instruction Cache Locking by Way (способ блокировки кэширования инструкций). кэш инструкций имеет 4 независимых бита блокировки (эти биты доступны в регистре IMEM_CONTROL), которые можно использовать для независимой блокировки четырех путей.
Когда отдельный путь заблокирован (установлен соответствующий бит ILOC в регистре IMEM_CONTROL), он не участвует в политике замены строки кэша. Инструкции, кэшированные из заблокированного пути, можно удалить только с помощью инструкции IFLUSH.
Примечание: блокировка кэша предотвращает от выбора для замены только достоверные строки кэша. Недостоверные строки кэша, сохраненные в заблокированном пути, все еще могут быть выбраны для замены. Это означает, что промахи кэша в недостоверную запись приведут к тому, что эта запись будет выбрана для замены новой строкой кэша.
Пример Example3 (3) (см. прикрепленный ZIP-файл [7]) демонстрирует, как более часто используемые функции (во внешней памяти) могут быть закэшированы и заблокированы, так что они не будут замены в кэше. Эта схема состоит из блокировки путей Way1, Way2, Way3 (путь Way0 разблокирован), и делается демонстрационный вызов интересующих функций. Функции будут кэшированы в Way0 (поскольку все другие пути заблокированы). Теперь Way0 может быть заблокирован (и Way1, Way2, Way3 могут быть разблокированы). Любые последующие промахи кэша могут заменить строки только разблокированных путей Way1..Way3 (путь Way0 заблокирован).
Блокировка всех 4 путей одновременно не рекомендуется.
Конфигурация памяти инструкций L1. Бит IMC управляет, сконфигурирован ли верхний 16 килобайтный банк памяти инструкций как кэш. Бит ENICPLB должен быть в 1, когда поддержка кэша разрешена.
Разрешение CPLB инструкций. С битом ENICPLB можно разрешить/запретить CPLB инструкций. Перед загрузкой новых данных данных дескриптора в любой CPLB, соответствующая группа из 16 CPLB должна быть запрещена с помощью бита ENICPLB.
Data Memory Control Register (DMEM_CONTROL). Рис. 20 показывает различные битовые поля и их функционал для регистра управления памятью данных DMEM_CONTROL.
DAG Port Preference. С двумя битами PORT_PREFx не кэшируемые выборки данных – которые исходят из генераторов адреса данных (Data Address Generators, DAG0 и DAG1) – могут быть привязаны к одному определенному порту DAG (Port A или Port B, см. рис. 1).
L1 Data Cache Bank Select. Бит DCBS управляет, используется ли бит 14 или бит 23 адреса для переключения между банками Bank A и Bank B для доступа кэша (см. рис. 20).
Конфигурация памяти данных L1. Биты DMC разрешают/запрещают поддержку кэша для банков памяти данных L1. Бит DMC[1] управляет Bank A, и DMC[0] управляет Bank B. Поддерживается конфигурирование Bank A или Bank A + Bank B в качестве кэша. Только Bank B не может быть сконфигурирован как доступный как память кэша данных L1. Бит ENDCPLB должен быть в 1, когда разрешена поддержка кэша.
Примечание: некоторые процессоры Blackfin не имеют 2 банка данных, так что не поддерживают биты DCBS и DMC[0] (см. таблицу 2).
Data CPLB Enable. С битом ENDCPLB могут быть разрешены/запрещены CPLB данных. Перед загрузкой новых дескрипторов данных в любой CPLB, соответствующая группа из 16 CPLB должна быть запрещена с помощью бита ENDCPLB.
Рис. 19. Битовые поля и их функциональность для регистра управления IMEM_CONTROL.
Рис. 20. Битовые поля и их функциональность для регистра управления DMEM_CONTROL.
[Инструкции управления кэшем]
Instruction Cache Invalidation (перевод кэша в недостоверное состояние). Путем вывода из достоверности строк кэша, связанных в буфером, поддерживается "когерентность" (синхронность) между содержимым, которое хранится в кэше, и актуальным содержимым исходной памяти, которая кэшируется. Есть 3 схемы для перевода в недостоверность кэша инструкций:
• Инструкция IFLUSH может использоваться для перевода в недостоверное состояние определенного адреса в карте памяти. Когда выполняется инструкция IFLUSH [P2];, если адрес памяти, на который указывает P2, находится в кэше, то соответствующая строка кэша будет сделана недостоверной после выполнения вышеупомянутой инструкции. Когда используется инструкция наподобие IFLUSH [P2++];, указатель инкрементируется на размер строки кэша.
• Бит VALID секции тэга для любой строки в кэше может быть явно очищен записью лог. 1 в секцию тэга. Значение в тэг секции может быть записано с помощью регистра ITEST_COMMAND. Это подробно рассматривается в следующем разделе.
• Чтобы сделать недостоверным весь кэш, может быть очищен бит IMC в регистре IMEM_CONTROL. Этот бит очищает бит VALID для всех секций тэга кэша. Бит IMC можно установить, чтобы снова разрешить кэш.
Инструкции управления кэшем данных
• Может использоваться инструкция PREFETCH для выделения строки в кэше L1.
• Инструкция FLUSH приводит к синхронизации (сбросу) данных кэша, чтобы указанная строка кэша совпадала по содержимому с оригинальными данными внешней памяти. Если строка кэша грязная, инструкция записывает строку обратно во внешнюю память, и помечает эту строку в кэше данных как чистую.
• Инструкция FLUSHINV делает с кэшем данных то же самое, что и инструкция FLUSH, после чего переводи в недостоверное состояние указанную строку в кэше. Если строка не грязная, то сброса данных кэша не будет. В этом случае произойдет только шаг перевода строки кэша в недостоверное состояние.
[Получение доступа к памяти кэша]
Когда банк память L1 сконфигурирован как кэш, к нему не могут напрямую обратиться ядро или DMA. Операции чтения/записи на пространстве кэша могут быть выполнены с использованием регистров ITEST_COMMAND и DTEST_COMMAND. Регистр DTEST_COMMAND также может использоваться для доступа к банкам SRAM инструкций. Рис. 21 показывает битовые поля регистра ITEST_COMMAND, рис. 22 показывает битовые поля регистра DTEST_COMMAND.
Доступ к кэшу инструкций. Регистр ITEST_COMMAND может использоваться для доступа к данным или секциям тега строк кэша инструкций.
Строка кэша поделена на четыре 64-битных слова. Для доступа может быть выбрано любое из этих 4 слов. При чтении кэша значение данных читается в наборе регистров ITEST_DATA[1:0]. При записи кэша значение из набора регистров ITEST_DATA[1:0] записывается в кэш.
Когда осуществляется доступ к секции тэга, то 32-битное значения тэга передается через (в/из) регистр ITEST_DATA0.
Рассмотрим пример, где значение 0x0C010360 записывается в регистр ITEST_COMMAND. Эта инструкция будет читать секцию тэга из way-3, set-27, subbank-1 и передавать это в регистр ITEST_DATA0. Подобным образом запись 0x0C010362 передает содержимое регистра ITEST_DATA0 в секцию тега строки, размещенной в way-3, set-27, subbank-1. При доступе к секции тэга (чтение или запись), биты 3 и 4 регистра ITEST_COMMAND зарезервированы.
Запись значения 0x0C010374 будет читать второе слово строки кэша, размещенной в way-3, set-27, subbank-1 и передавать это в набор регистров ITEST_DATA[1:0]. Запись значения 0x0C010366 в регистр ITEST_COMMAND передает значение набора регистров ITEST_DATA[1:0] в word-0 строки кэша way-3, set-27, subbank-1 кэша инструкций. При записи кэша регистр ITEST_DATA[1:0] должен быть загружен перед записью регистра ITEST_COMMAND.
Доступ к SRAM инструкций. Когда установлен бит 24 в регистре DTEST_COMMAND, регистр DTEST_COMMAND может использоваться для доступа к instruction SRAM. 64-битное слово может быть передано через набор регистров (в/из) DTEST_DATA[1:0] для записи/чтения instruction SRAM. Таким образом, к памяти можно получить доступ порциями по 8 байт за раз.
Бит 2 регистра DTEST_COMMAND должен быть установлен при работе в этом режиме. Биты 3-10 должны быть назначены с битами адреса, куда осуществляется доступ. Рассмотрим случай, когда байт по адресу 0xFFA07935 читается из памяти инструкций. Этот адрес лежит в банке bank-1. При доступе к вышеуказанному байту будет осуществлен доступ стазу к целому блоку байт (0xFFA07930 – 0xFFA07937). Управляющее значение, которое должно быть загружено в регистр DTEST_COMMAND будет 0x05034134.
Доступ к кэшу данных. Когда очищен бит 24 регистра DTEST_COMMAND, регистр DTEST_COMMAND может использоваться для доступа к данным или секциям тэга строк кэша данных. Слово из секции данных строки кэша может быть передано через (в/из) набор регистров DTEST_DATA[1:0].
При доступе к секции тега 32-битное значение тэга передается через (в/из) регистр DTEST_DATA0.
Рассмотрим пример, где значения набора регистров DTEST_DATA[1:0] нужно записать в word-0 строки кэша way-1, set-39, subbank-0, банк данных кэша bank-A. Тогда в регистр DTEST_COMMAND можно записать значение 0x040004E5. Набор регистров DTEST_DATA[1:0] должен быть загружен перед записью в регистр DTEST_COMMAND. Бит 14 регистра DTEST_COMMAND зарезервирован при доступе к пространству кэша данных (бит 24 = 0).
Рис. 21. Битовые поля и их функциональность для регистра ITEST_COMMAND.
Рис. 22. Битовые поля и их функциональность для регистра DTEST_COMMAND.
[Соображения производительности]
В этом разделе рассмотрены результаты сравнения быстродействия работы программы с использованием кэша и без него. Эти примеры применяются к специальным сценариям, и дают идеи, как получить лучшую производительность в определенных рабочих условиях.
Для этих частных примеров на оценочной плате разработчика (ADSPBF533 EZ-KIT Lite® evaluation board) блок PLL сконфигурирован на частоту ядра 270 МГц (CCLK) и частоту системной шины 54 МГц (SCLK) соответственно (CLKIN = 27 МГц).
кэш инструкции: оптимизированные условия. Для линейного выполнения кода во внешней памяти производительность можно увеличить с выигрышем до 13% (см. врезку "Задержка при выборке инструкции, сравнение работы с кэшем и без кэша") в сравнении с кодом, который не сохранен в кэше. Если инструкции уже скопированы в кэш, и выполнены как минимум дважды, возможно ускорение больше 50%. В таблице 9 показано сравнение (время выполнения указано в тактах ядра), когда функции выполняются от 1x до 1000x раз (например, в алгоритме фильтра) и кэш инструкции выключается и включается соответственно. Числа – показывающие количество тактов ядра – получены из кода Example6 (6). Столбец "Выигрыш" показывает экономию циклов ядра (в процентах). Числа могут меняться ±100 циклов при выполнении нескольких прогонов теста (например, при обновлении SDRAM).
Таблица 9. Производительность кэша инструкций в хороших условиях.
Колич. выполнений
кэш инструкций ВЫКЛ
кэш инструкций ВКЛ
Выигрыш
1x
1430
1245
12.9%
2x
2480
1329
46.4%
4x
4580
1469
67.9%
8x
8740
1973
77.4%
10x
10814
2173
79.9%
100x
104620
11850
88.7%
1000x
1042950
109050
89.5%
кэш инструкции: плохая концепция. Таблица 10 показывает числа, подобные числам из предыдущего примера. Но теперь код не выполняется линейно (в каждой функции содержится просто инструкция перехода jump), и будет происходить множество промахов кэша и замен строк кэша. Каждый промах кэша приводит к операции заполнения строки кэша. Если функция просто содержит инструкцию перехода, и теперь больше нет преимущества линейного кода, когда в кэше уже есть нужный код, то дополнительные выборки кода из внешней памяти и загрузки его в кэш требуют затрат времени.
Таблица 10. Производительность кэша инструкций с плохой концепцией выполнения кода.
Колич. выполнений
кэш инструкций ВЫКЛ
кэш инструкций ВКЛ
Проигрыш
1x
1031
1164
-12.9%
2x
1924
2394
-24.4%
4x
3747
4654
-24.2%
8x
7462
8918
-19.5%
10x
9314
11100
-19.2%
100x
91643
109201
-19.2%
1000x
915488
1090127
-19.1%
кэш данных. Размер страницы установлен в The 1 килобайт. Сначала ядро записывает 15 килобайт во внешнюю память и затем читает данные обратно; 32-битный доступ осуществляется в один и тот же внутренний банк. С такой настройкой не будут срабатывать замены CPLB. Бит DCBS не относится к этому случаю, для кэша используется только L1 Data Bank A, и все данные можно хранить без необходимости замены данных в кэше (в реальности подобное, увы, встречается редко).
Замена CPLB может стоить несколько сотен тактов (обработка исключения, алгоритм замены строки кэша и т. д.). Важна хорошая стратегия для настройки таблицы CPLB.
Таблица 11. Быстродействие кэша данных.
Запись памяти
Чтение памяти
Без кэша данных
23039
55248
кэш Write-Back
10572
3866
кэш Write-Through, AOW=0
23039
10583
кэш Write-through, AOW=1
32154
3866
В таблице 11 показаны результаты, представленные в затраченных тактах ядра:
• Запись в память без разрешенного кэша и кэшем стратегии типа write-through (выделение строки кэша только на чтение) показывают отсутствие отличий. • Операция записи в память со стратегией write-back требует больше тактов на дополнительные заполнения строки кэша. • Запись в память, когда бит AOW установлен, кэш стратегии write-through имеет быстродействие хуже, чем когда осуществляется доступ во внешнюю память в первый раз (все строки кэша недостоверны). • Чтение памяти в режиме кэша write-back mode и write-through с установленным битом AOW дают лучшую производительность, когда данные уже сохранены в память кэша. • Чтение памяти в режиме кэша write-through с установленным битом AOW не показывает выгоду из пакетного заполнения строки кэша (cache-line burst fill). • Чтение памяти без разрешенного кэша показывает самую худшую производительность в сравнении с остальными сценариями.
Частота ядра (CCLK) против частоты системной шины (SCLK). С нерациональными соотношениями между частотами CCLK и SCLK может наблюдаться потеря производительности. Рис. 23 показывает выборку инструкции, начиная с адреса shows 0x00h, когда разрешен кэш инструкций. Соотношение CCLK:SCLK = 3:1 или больше должно предпочтительно использоваться, когда применяется кэш. Это требует 22 такта SCLK.
Соотношение между частотой ядра и частотой шины 2:1. На каждое второе слово вставляется дополнительный такт SCLK. Около 28 тактов SCLK требуется для выборки целой строки кэша (включая команду активации).
Соотношение 1:1 снижает полосу пропускания. В этом случае требуется вставка 2 дополнительных тактов SCLK с каждым вторым словом (см. рис. 24). Требуется около 36 тактов SCLK.
Эти отличия показывают время, которое ядро требует на сравнение тэгов кэша, на выравнивание инструкции в блоке выравнивания, и наконец на выполнение инструкции.
[Обновление SDRAM]
Рис. 25 показывает ситуацию, где заполнение строки кэша прервано обновлением динамической памяти. Передача останавливается, и контроллер памяти (в режиме автообновления, autorefresh) выдает команду precharge (закрывает строку/страницу) и команду refresh. После завершения передача продолжается со следующего инкремента последнего адреса.
Когда SDRAM находится в режиме самообновления (self-refresh mode), процессор все еще обращается к памяти. В этом случае SDC оставляет режим self-refresh к либо временному auto-refresh или простому auto-refresh, в зависимости от состояния бита SRFS в регистре EBIU_SDGCTL.
[Производительность SDRAM]
Больше информации по производительности SDRAM с контроллером SDC процессора Blackfin можно найти в разделе "External Bus Interface Unit" руководства ADSP-BF537 Blackfin Processor Hardware Reference (или см. [4] для процессора ADSP-BF538). Доступ на чтение/запись со стороны DAG требует соответственно 8/1 тактов SCLK на 16-битное слово. Выборка инструкции и заполнение строки кэша требуют около 1.1 тактов SCLK на 16-битное слово.
Выводы:
• Код должен быть написан линейно, чтобы утилизировать достоинства пакетного заполнения строки кэша (cache-line burst fill, pre-fetch). • Код нужно использовать повторно, чтобы сделать кэш привлекательнее.
Рис. 23. Выборка инструкции при включенном кэше (CCLK:SCLK = 2:1).
Рис. 24. Выборка инструкции при включенном кэше (CCLK:SCLK = 1:1).
Рис. 25. Выборка инструкции при включенном кэше (прерванная операцией auto-refresh).
Инструментарий VisualDSP++® поддерживает управление кэшированием памяти. Ниже рассмотрены его некоторые функции. Подробную информацию можно найти в руководстве VisualDSP++ C/C++ Compiler and Library Manual for Blackfin Processors [5]. кэширование для инструкций и для данных можно разрешить одновременно или по отдельности, и можно индивидуально сконфигурировать для них место в памяти под кэш.
Файлы заголовков. Файлы хедеров VisualDSP++ def_LPBlackfin.h и cplb.h предоставляют дружественные для пользователя макросы и маски для конфигурирования CPLB и другие возможности. Значение 0x0C010366 в одном из предыдущих примеров может выглядеть следующим образом:
Управление CPLB. Поддержка CPLB управляется через глобальную целочисленную переменную ___cplb_ctrl. Это стандартное имя языка C имеет 2 начальных символа подчеркивания, и его соответствующее имя на языке ассемблера имеет 2 начальных символа подчеркивания. Значение этой переменной определяет, разрешает ли код первоначальной настройки (startup code) систему CPLB. По умолчанию переменная имеет нулевое значение, это показывает, что CPLB не разрешены. Должна использоваться прагма pragma retain_name вместе с __cplb_ctrl, чтобы эта переменная не была уничтожена компилятором, когда разрешена оптимизация.
Значение переменной ___cplb_ctrl можно поменять следующими методами:
• Эта переменная может быть определена как новая глобальная с инициализированным значением. Это определение переназначает определение, заданное в библиотеке. • Слинкованная версия переменной может быть изменена в отладчике, после загрузки приложения но перед его запуском, чтобы код первоначальной настройки (startup code) увидел новое значение. Для последнего варианта нужна ручная правка startup code.
Когда кэширование разрешено использованием ___cplb_ctrl, также указывается императив USE_CACHE.
Инсталляция CPLB. Когда переменная ___cplb_ctrl показывает, что CPLB разрешены, то startup code вызывает подпрограмму _cplb_init. Эта подпрограмма настраивает CPLB инструкций и данных из таблицы, и разрешает работу аппаратуры защиты памяти. Конфигурационные таблицы по умолчанию определены в файлах с именем cplbtabn.s, которые находятся к каталоге VisualDSP\Blackfin\lib\src\libc\crt, где n соответствует модели процессора Blackfin.
Когда кэш разрешена, конфигурация инсталлируется CPLB по умолчанию, определенная в вышеуказанном файле. Но Вы можете изменить указанные файлы, чтобы задать свою собственную конфигурацию CPLB. Предоставленный файл должен быть подключен в проект, чтобы изменения вступили в силу. В проекте Example5 (5) демонстрируется, как можно модифицировать конфигурационную таблицу CPLB.
Обработка исключений. Как уже обсуждалось раньше, в сложной модели памяти может понадобиться большее количество CPLB, чем может быть активно одновременно. В таких системах будут время от времени происходить ситуации, когда приложение потребует доступа к памяти, которая пока не покрывается активными CPLB. Такие ситуации будут вызывать исключение промаха кэша (CPLB miss exception).
Библиотека VisualDSP++ включает подпрограмму обработчика для обслуживания исключений CPLB таких ситуаций, _cplb_mgr. Эта подпрограмма должна быть вызвана из обработчика исключения, который определил событие промаха CPLB, независимо от того, был ли это промах данных или промах инструкции. Подпрограмма _cplb_mgr идентифицирует неактивный CPLB, который должен быть установлен чтобы реализовать доступ через кэш, и заменить этой записью CPLB одну из текущих активных записей CPLB. Если CPLB разрешены, то код запуска (startup code) по умолчанию включено устанавливает обработчик исключения по умолчанию, который называется called _cplb_hdr; он ничего не делает кроме проверки события промаха CPLB, которое делегируется в _cplb_mgr. Подразумевается, что у пользователей есть свои собственные обработчики для обработки дополнительных событий [6].
Использование Project Wizard. Мастер проекта предоставляет возможность создания проекта, включающего поддержку защиты памяти и кэша как для памяти инструкций, так и данных. Рис. 26..30 показывают дополнительные нужные действия:
1. Должны быть добавлены файлы .LDF и startup code (рис. 26).
2. Должна быть добавлена поддержка внешней памяти (SDRAM) и выбран размер используемой памяти (рис. 27).
Рис. 27. Project Wizard: настройки внешней памяти для LDF.
3. В разделе настроек "Cache and Memory Protection" может быть добавлена поддержка для защиты памяти и поддержка для кэша как для памяти инструкций, так и памяти данных (рис. 28). Могут быть сгенерированы настраиваемые таблицы CPLB, и Вы можете выбрать стратегию работы кэша данных между write-through или write-back. Опция "Cache mapping set size" управляет битом DCBS в регистре DMEM_CONTROL.
Рис. 28. Project Wizard: настройка кода запуска, установка кэша и защиты памяти (Startup Code Settings: Cache and Memory Protection).
4. Все настройки можно модифицировать в диалоговом окне Project Options. После сохранения настроек и перед перекомпиляцией файлы кода запуска и настроек линкера перегенерируются заново (рис. 29).
После окончания настройки проекта будут сгенерирован подключаемый файл для проекта, который будет называться имяпроекта_cplbtab.c (Generated Files -> Startup). Этот файл содержит конфигурируемую таблицу CPLB (рис. 30).
Для управления памятью процессоров Blackfin используются следующие отображенные на память регистры (memory-map registers, MMR):
Table 12. Регистры MMR для настройки CPLB.
IMEM_CONTROL
DMEM_CONTROL
ITEST_COMMAND
DTEST_COMMAND
ITEST_DATA [1:0]
DTEST_DATA [1:0]
ICPLB_DATA [15:0]
DCPLB_DATA [15:0]
ICPLB_ADDR [15:0]
DCPLB_ADDR [15:0]
ICPLB_STATUS
DCPLB_STATUS
ICPLB_FAULT_ADDR
DCPLB_FAULT_ADDR
[Конфигурация кэша для различных моделей процессоров Blackfin]
Здесь демонстрировалась конфигурация управления кэшем для процессоров ADSP-BF533. Все, что там было рассмотрено, можно применить и для процессоров ADSP-BF531 и ADSP-BF532. Код примеров (1)..(5) можно также использовать для процессоров ADSP-BF531 и ADSP-BF532. Примеры кода (6) и (7), поставляемые с этим апноутом, можно использовать для всех одноядерных моделей процессоров Blackfin. Размер памяти инструкций, конфигурируемой под кэш, в настоящее время для всех одноядерных процессоров Blackfin одинаковый (16 килобайт).
Большинство одноядерных процессоров Blackfin поддерживают два банка данных L1, конфигурируемых как кэш, каждый размером 16 килобайт. У процессора ADSP-BF531 есть только один банк данных.
У двухядерного процессора ADSP-BF561 объем кэша вдвое больше, чем у процессора ADSP-BF533.
[Заключение]
В этом документе рассматривалось конфигурирование кэша инструкций и данных для процессоров Blackfin. Также рассматривалась привязка строк кэша к адресам памяти. Предоставленные примеры кода (1)..(8) [7] демонстрируют, как настроить дескрипторы CPLB для памяти инструкций и данных, как разрешить/запретить кэш инструкций/данных, и как обработать исключения CPLB и сделать блокировку кэша инструкций по пути (way). Также рассмотрен доступ к памяти кэша инструкций/данных со стороны ядра через команды ITEST_COMMAND и DTEST_COMMAND.
Вместе с этим апноутом Analog Devices поставляет ZIP-файл [7], в котором находятся примеры кода. Он содержит следующие примеры:
(1) Example1, код для конфигурирования дескрипторов CPLB и кэша инструкций/данных (язык C). (2) Example2, код для обработки исключения CPLB (язык C). (3) Example3, код для блокировки кэша инструкций по пути (язык C). (4) Example4, код демонстрации инструкций управления кэшем данных (язык C). (5) Example5, код демонстрации поддержку компилятора VisualDSP++ для кэша Blackfin (язык C). (6) Example6, код для конфигурирования дескрипторов ICPLB и кэша инструкций (язык ассемблера Blackfin). (7) Example7, код для конфигурирования дескрипторов DCPLB и кэша данных (язык ассемблера Blackfin). (8) Example8, код для плохой концепции построения кода с точки зрения кэширования инструкций (язык ассемблера Blackfin).
[1] ADSP-BF533 Blackfin Processor Hardware Reference. Rev 3.6, February 2013. Analog Devices, Inc.
[2] Computes Architecture A Quantitative Approach. Second Edition, 2000 David A. Patterson and John L. Hennessy.
Всю упомянутую в статье документацию и примеры исходного кода можно скачать с сайта компании Analog Devices, или по ссылке [7].
[Словарик]
CCLK тактовая частота ядра процессора.
CLKIN входная частота кристалла, которая проходит через внутреннее умножение и деление, после чего получаются частоты ядра (CCLK) и шины (SCLK).
MMR Memory-Mapped Register - регистр, отображенный на адресное пространство процессора Blackfin. Обычно используется для обмена данными с различными периферийными устройствами кристалла процессора.
MPCU Memory Protection and Cache Unit, блок защиты памяти и кэширования процессора Blackfin.
PLL Phase Locked Loop, петля фазовой подстройки частоты, ФАПЧ. Применяется для синтеза внутренних тактовых частот процессора (CCLK, SCLK).
SCLK тактовая частота шины процессора, используется для тактирования всех периферийных устройств. Благодаря этому все периферийные устройства (таймеры, интерфейсы) работают синхронно и отдельно от потока выполнения кода ядра.
SDC контроллер синхронной динамической внешней памяти.