新書推薦:
《
中年处男:一份日本社会纪实报告
》
售價:NT$
230.0
《
行动的勇气,畅销书作家弘丹主编,30余位大咖分享人生高效秘诀。
》
售價:NT$
301.0
《
人生财富靠康波
》
售價:NT$
556.0
《
富人是怎么赚钱的
》
售價:NT$
347.0
《
时刻人文·富与穷:英国政治经济学思想史(1750—1834)(探索学术大师的思想宫殿,挖掘学术名著的知识宝藏,重新理解政治经济学的学术源流)
》
售價:NT$
500.0
《
影像中的侦查学:刑侦警务类节目研究
》
售價:NT$
245.0
《
俄国社会阶层与历史变迁(1700—1900)(通过本书可更加深刻地理解以贵族为代表的俄国社会各阶层的历史意义)
》
售價:NT$
449.0
《
博弈与平衡:奥格斯堡城市宗教改革研究(1518-1537)
》
售價:NT$
551.0
|
編輯推薦: |
1.本书由浅入深、概念齐全、实践性强、指导性强,结合了多年多核软件开发的实际经验,对多核设计中常见的问题进行了详细的描述。2.本书从基本概念出发,层层推进,介绍了多核并行、数据传输与处理并行和多层次并行设计的经验,是多核DSP并行软件开发者必备的参考书。
|
內容簡介: |
本书系统介绍了C66x多核软件开发的知识,并基于C6678的设计实例介绍了相关设计经验。系统介绍了C66x DSP器件的基础概念和多核软件设计的基础知识,引领读者循序渐进地掌握多核软件设计技术。对于传统DSP开发人员比较陌生的一些概念,如Cache、预取、数据一致性、数据依赖、死锁等,进行了重点描述。系统介绍了C66x多核器件的存储器、DMA传输、中断等内容,并结合工作实际,介绍了多核软件优化、多核并行设计及任务级优化经验。*后,以多普勒成像的设计实例描述了如何实现并行设计。 全书共11章,内容包括C66x DSP的基本组成,如存储器组织、DMA传输、中断和异常、Cache缓存和数据一致性等,并包含CCS软件开发环境、SYSBIOS实时操作系统、多核并行设计、软件设计优化等相关知识。 本书的特点是由浅入深、概念齐全、实践性强、指导性强。本书结合了多年多核软件开发的实际经验,对多核设计中常见的问题进行了详细的描述; 从基本概念出发,层层推进,介绍了多核并行、数据传输与处理并行和多层次并行设计的经验。 对于从事C66x多核软件开发的设计师,本书具有很强的指导意义,本书还适合作为高校计算机、数据处理、信号处理、通信等相关专业的本科和研究生教材。
|
目錄:
|
目录
第1章TI多核C66x DSP介绍
1.1C6678处理器
1.1.1C6678概览
1.1.2外围设备
1.266AK处理器
1.366AK2H141206和C6678各项功能对比
1.4C66x处理器内核
1.5电源休眠控制器
1.5.1C66x内核电源休眠管理介绍
1.5.2电源休眠管理特征
1.6锁相环及其设置
1.6.1主PLL和PLL控制器
1.6.2DDR3 PLL
1.6.3PASS PLL
1.7C6678处理器接口通信相关外围设备
1.7.1I2C外围设备
1.7.2SPI 外围设备
1.7.3HyperLink 外围设备
1.7.4UART 外围设备
1.7.5PCIE 外围设备
1.7.6TSIP 外围设备
1.7.7包加速器
1.7.8EMIF16外围设备
1.7.9安全加速器
1.7.10Gigabit Ethernet开关子系统
1.7.11管理数据输入输出
1.7.12串行RapidIO端口
1.7.13通用目的输入输出
1.8定时器
1.9信号量
1.10多核导航器
1.11设计建议
1.11.1初始化
1.11.2接口驱动程序
1.11.3时间戳的获取
1.11.4EVM板的使用
第2章C66x存储器组织
2.1C66x存储控制器
2.1.1L1P存储控制器
2.1.2L1D存储控制器
2.1.3L2存储控制器
2.1.4外部存储控制器
2.1.5扩展存储控制器
2.2多核共享存储控制器
2.2.1概览
2.2.2C66x内核从接口
2.2.3系统从接口
2.2.4系统主接口
2.2.5外部存储器主接口
2.2.6MSMC存储器
2.3扩展存储控制器XMC
2.3.1存储器映射寄存器概要
2.3.2XMC 存储器保护和地址扩展
2.3.3存储器保护和地址扩展过程
2.3.4地址扩展
2.3.5XMC存储器保护结构支持
2.3.6预取缓冲
2.4存储器保护架构
2.4.1存储器保护的目的
2.4.2特权级别
2.4.3存储器保护架构
2.5带宽管理
2.5.1介绍
2.5.2带宽管理架构
2.5.3带宽管理寄存器
2.6设计建议
2.6.1合理规划使用存储器
2.6.2存储器设置成不被Cache缓存和预取
第3章Cache缓存和数据一致性
3.1为什么使用Cache
3.2C64x和C66x DSP之间的Cache区别
3.3Cache 存储器结构概览
3.4Cache基础知识
3.4.1直接映射CacheL1P Cache
3.4.2Cache缺失的类型
3.4.3组相联 Cache
3.4.4二级Cache
3.5L1P Cache
3.5.1L1P存储器和Cache
3.5.2L1P Cache结构
3.5.3L1P冻结模式
3.5.4程序启动的一致性操作
3.6L1D Cache
3.6.1L1D存储器和Cache
3.6.2L1D Cache结构
3.6.3L1D 冻结模式
3.6.4程序发起的Cache一致性操作
3.7L2 Cache
3.7.1L2存储器和Cache
3.7.2L2 Cache结构
3.7.3L2 冻结模式
3.7.4程序发起的Cache一致性操作
3.7.5Cache能力控制
3.8使用Cache
3.8.1配置L1 Cache
3.8.2配置L2 Cache
3.9数据一致性
3.9.1Snoop 一致性协议
3.9.2在外部存储器和Cache之间维持一致性
3.9.3对L2 Cache一致性操作使用指导
3.9.4对L1 Cache一致性操作使用指导
3.10片上Debug支持
3.11在运行中改变Cache配置
3.11.1禁用外部存储器Cache功能
3.11.2在运行中改变 Cache尺寸
3.12优化Cache性能
3.12.1Cache 性能特征
3.12.2阻塞情况
3.12.3优化技术概览
3.12.4应用级优化
3.12.5过程级优化
3.12.6C66x DSP Cache一致性操作小结
3.13设计建议
3.13.1消除虚假地址
3.13.2数据一致性问题
第4章DMA传输
4.1IDMA
4.1.1IDMA 结构
4.1.2IDMA通道 0
4.1.3IDMA 通道1
4.2EDMA3 控制器
4.2.1EDMA3 控制器介绍
4.2.2EDMA3 器件特定的信息
4.2.3EDMA3 通道控制器配置
4.2.4EDMA3 传输控制器配置
4.2.5EDMA3 通道同步事件
4.2.6EDMA3 通道控制器
4.2.7EDMA3 传输控制器
4.3EDMA3传输类型
4.3.1A同步传输
4.3.2AB同步传输
4.4参数RAM
4.4.1PaRAM参数集
4.4.2Dummy 与Null传输比较
4.4.3参数集更新
4.4.4连接传输
4.4.5常数地址模式传输对齐问题
4.4.6单元大小
4.5发起一个 DMA传输
4.5.1DMA 通道
4.5.2QDMA 通道
4.5.3完成一个DMA传输
4.6提升DMA性能的几点建议
4.6.1尽量用较大的ACNT
4.6.2线性传输
4.6.3地址对齐
4.6.4恰当使用多个CC和TC传输
第5章中断和异常
5.1C6678处理器中断简介
5.2芯片中断控制器
5.3C66x 内核中断控制器概述
5.3.1特征
5.3.2功能块图
5.4中断控制器结构
5.4.1事件寄存器
5.4.2事件合并器
5.4.3中断选择器
5.4.4异常合并器
5.5C66x 内核事件
5.6中断控制器与DSP交互
5.6.1DSP 中断控制器接口
5.6.2DSP 服务中断事件
5.7中断设计建议
5.7.1不要过多使用中断或中断嵌套
5.7.2中断服务程序中代码不宜过长
5.7.3中断服务程序改变的全局变量要加上volatile标志
第6章如何使用CCS
6.1常用界面
6.1.1Project Explorer
6.1.2程序窗口
6.1.3目标配置窗口
6.1.4Debug 窗口
6.1.5Memory 窗口
6.1.6Expressions窗口
6.1.7Breakpoints窗口
6.1.8Problems窗口
6.1.9Console窗口
6.2新建工程
6.3新建一个目标配置文件
6.3.1新建ccxml文件
6.3.2设置仿真器
6.3.3添加器件
6.4常用操作
6.4.1Launch
6.4.2Group
6.4.3Connect
6.4.4加载程序
6.4.5设置断点调试程序
6.4.6复位
6.5常见问题
6.5.1头文件找不到
6.5.2EVM板未初始化,调试找不到DDR3
6.5.3选中不了仿真器
6.5.4加断点调试错误
6.5.5域选择不正确
6.5.6仿真器连接中断电
6.6设置字体和代码风格
6.6.1修改字体
6.6.2代码风格设置
6.7MCSDK
6.7.1MCSDK架构
6.7.2MCSDK 特点
6.8TI函数库调用
6.8.1格式选择
6.8.2库的调用
6.8.3库的使用
6.9理解CMD文件
6.9.1CMD文件简介
6.9.2MEMORY命令
6.9.3SECTIONS命令
第7章SYSBIOS实时操作系统
7.1什么是SYSBIOS
7.1.1SYSBIOS的优势
7.1.2SYSBIOS和XDC TOOL的关系
7.2SYSBIOS包
7.3SYSBIOS中使用C
7.3.1存储器管理
7.3.2Name Mangling
7.3.3从配置调用对象方法
7.3.4类构造器和析构器
7.4SYSBIOS配置和编译
7.4.1在工程中添加SYSBIOS支持
7.4.2创建一个独立的配置工程
7.4.3配置SYSBIOS 应用
7.4.4用XGCONF打开一个配置文件
7.4.5用XGCONF执行任务
7.4.6保存配置
7.4.7关于XCONFG视图
7.4.8使用可用产品视图
7.4.9使用概要视图
7.4.10使用属性视图
7.4.11使用问题视图
7.4.12找到并修正错误
7.5编译一个SYSBIOS应用
7.5.1了解编译流程
7.5.2编译和连接优化
7.6线程模块
7.6.1SYSBIOS 启动顺序
7.6.2线程模块的概览
7.6.3线程类型
7.6.4线程优先级
7.6.5让步和抢占
7.6.6钩子
7.7硬件中断
7.7.1创建中断
7.7.2硬件中断嵌套和系统堆栈大小
7.7.3硬件钩子
7.8软件中断
7.8.1创建软件中断对象
7.8.2设置软件中断优先级
7.8.3软件中断优先级和系统堆栈大小
7.8.4软件中断执行
7.8.5优点和折中
7.8.6软件中断函数同步
7.8.7软件钩子
7.9任务
7.9.1创建任务
7.9.2任务执行状态和调度
7.9.3任务堆栈
7.9.4测试堆栈溢出
7.9.5任务钩子
7.9.6空闲循环
7.10SYSBIOS同步模块
7.10.1信号量
7.10.2事件模块
7.10.3门模块
7.10.4邮箱
7.10.5队列
7.11定时服务
7.12Memory
7.12.1新建一个Platform
7.12.2栈
7.12.3Cache配置
7.12.4Cache Runtime API
7.12.5动态存储器分配
7.12.6Heap的实施
7.13硬件抽象层
7.14典型设计实例和建议
7.14.1典型设计
7.14.2设计建议
第8章多核并行设计
8.1并行粒度和并行级别
8.2并行方式
8.3任务类型
8.3.1相同任务的多个副本
8.3.2多个独立任务
8.3.3单个任务拆分成多个子任务
8.3.4多个松散耦合任务
8.3.5耦合度高的任务
8.4依赖关系
8.4.1数据依赖
8.4.2存储器依赖
8.5死锁和活锁
8.5.1死锁
8.5.2活锁
8.6同步
8.6.1SYSBIOS同步模块
8.6.2采用控制信号实现多核对等同步
8.7forkjoin
8.8OpenMP并行设计
8.9任务级优化设计
8.9.1一种典型的任务处理流程
8.9.2优化设计实例
第9章软件优化设计
9.1for循环优化
9.1.1移出能在循环外完成的计算
9.1.2循环体内的大运算换成小运算
9.1.3多重循环
9.1.4for循环中有判断
9.2多核for循环并行任务优化
9.2.1资源占用小的for循环
9.2.2资源占用大的for循环
9.3if声明优化
9.3.1if转换
9.3.2消除if声明
9.3.3相同代码合并减少if声明
9.3.4减少嵌套的if
9.3.5优化条件表达式
9.3.6优化稀疏矩阵
9.4软件流水
9.5正确使用编译指示和关键字
9.5.1restrict关键字
9.5.2nassert关键字
9.5.3interrupt中断关键字
9.5.4near和far关键字
9.5.5const关键字
9.5.6UNROLL编译指示
9.5.7MUST_ITERATE编译指示
9.5.8CODE_SECTION 编译指示
9.5.9DATA_SECTION编译指示
9.5.10SET_CODE_SECTION和SET_DATA_SECTION编译指示
9.5.11DATA_ALIGN 编译指示
9.5.12STRUCT_ALIGN
9.6采用内建函数
9.6.1数据移动和打包函数
9.6.2使用除法指令
9.6.3使用C66x定点指令实现复数矩阵操作和向量操作
9.6.4浮点和矢量运算
9.7选定正确的优化级别
9.8软件优化小结
第10章距离多普勒成像设计实例
10.1背景介绍
10.2距离多普勒成像算法
10.3数据组织形式
10.4算法的并行化设计
10.5forkjoin的设计
10.6脉冲压缩的设计
10.6.1IFFT转为FFT
10.6.2无缓存的大点数FFT、IFFT设计
10.6.3有数据缓冲多核大点数FFT、IFFT设计
10.6.4资源使用情况
10.6.5复数相乘
10.6.6脉冲压缩的伪码实现
10.7其他阶段任务分解
10.8实验结果分析
第11章展望
11.1异构多核SOC处理器
11.1.1异构多核DSP
11.1.2异构多核FPGA
11.2嵌入式软件设计思考
11.2.1掌握系统架构
11.2.2做好软件模块化设计
11.2.3片上系统架构设计的挑战
11.2.4自动化并行设计
附录A
附录B
附录C
参考文献
|
內容試閱:
|
前言 C66x是TI(Texas Instruments)公司推出的新一代处理器内核,包含定点和浮点计算能力,C66x包含 90个新指令用于提升浮点和矢量运算。TMS320C6678是基于C66x内核的8核处理器,66AK2Hx是基于ARM CortexA15和C66x内核的异构多核处理器。基于C66x内核的DSP处理器已经成为主流的高性能DSP。多核DSP的软件开发技术对DSP嵌入式软件开发人员具有一定的挑战性。多核任务划分、并行处理设计、同步设计以及Cache一致性等问题是多核并行设计的关键,良好的并行设计才能发挥C66x处理器的优势。通过多年的研究并结合工程设计实践,总结了C66x多核DSP并行开发技术经验和设计中一些经常遇到的问题。本书以C6678为例系统介绍了C66x多核DSP、数据一致性、CCS使用、SYSBIOS实时操作系统、多核并行设计和优化等设计方法,用一个设计实例完整地描述了从任务并行设计到具体实现的过程。在C66x多核软件设计中,程序员的软件设计思想、设计方法需要调整和提高。本书从程序员的工作需要和高校学生的学习需要出发,结合工作实际,详细叙述了多核软件开发技术。初学者可以循序渐进地建立基于C66x多核并行开发的概念,并积累优化设计的经验提高设计水平,一开始就设计出高性能的并行代码。每章内容要点如下:(1) 第1章主要介绍了C66x处理器,并以C6678为例介绍了处理器概况、处理器内核、外围设备、多核导航器等模块。(2) 第2章主要介绍了C6678存储控制器、多核共享存储控制器、外部存储控制器EMC、扩展存储控制器XMC、存储器保护架构、带宽管理等存储器相关内容。(3) 第3章主要介绍了Cache基础知识,C66x的各级Cache、Cache的使用、数据一致性等内容。(4) 第4章主要介绍了IDMA、EDMA使用的一些知识。(5) 第5章介绍了C66x中断控制器、内核事件以及中断控制器与DSP交互的相关知识。(6) 第6章介绍了如何使用CCS进行相关的操作和配置。(7) 第7章介绍了SYSBIOS实时操作系统,并给出了相关设计例程。(8) 第8章介绍了多核并行设计的相关问题,如并行粒度、并行方式、依赖关系、死锁活锁、同步等问题,并介绍了任务级优化设计的例子。(9) 第9章介绍了软件优化技术,如for循环优化、软件流水、编译指示和关键字的使用、内建函数的使用等。(10) 第10章介绍了一个多核软件设计的实例。(11) 第11章介绍了多核发展的趋势及一些思考。(12) 附录中列出了常用的存储器地址映射、MAR寄存器地址对照表和C6678 EDMACC事件列表。本书中关于TI C66x多核DSP的相关资料来源于TI相关网站,如TI官网(www.ti.com)、德州仪器在线技术支持社区(www.deyisupport.com)等,相关资料的最新版本可以从中查询。参与本书审校的有牛蕾、习建博、邓庆勇、郭琦、白晓慧、张玉营、潘勇先、朱鹏等,方志红、梁之勇、宋皓、顾庆远等在多核开发技术方面做出了很大贡献。为本书的形成及多核C66x DSP开发技术做出贡献的人还有很多,在这里一并致谢!多核开发技术发展迅速,基于C66x的多核开发技术难点较多,由于作者水平有限,书中难免有疏漏之处,欢迎读者指正。作者2017年2月于合肥
第3章Cache缓存和数据一致性
与其他处理器一样,基于C66x内核的处理器也存在内核处理能力与存储器容量不匹配的问题。越靠近内核,存储器的通信带宽要求越高,但容量也就越小; 越远离内核,处理器容量越大,但带宽也就越小。C66x处理器内核使用寄存器,其用到的存储器从内到外依次是L1L1P和L1D、L2 SRAM、MSM SRAML3、DDR3。如前所述,L1和L2位于C66x内核中,L3位于处理器中C66x内核外面,DDR3位于处理器外。为了缓解处理器内核和外部存储器的矛盾,采用了Cache机制来实现外部数据在靠近处理器内核的存储器中保留一份拷贝,处理器内核经常与该数据拷贝交互数据,而不是直接和外部存储器交互数据。本章首先介绍了为什么使用Cache、Cache存储器结构概览、Cache基础知识,然后对C66x的各个Cache进行了详细介绍,并介绍了使用Cache、数据一致性、片上Debug支持和运行中改变Cache配置等内容,最后介绍了如何优化Cache性能和一些设计建议。3.1为什么使用Cache从DSP应用的角度,拥有一个大容量、快速的片上存储器是非常重要的。然而,处理器性能的提升比存储器发展的步伐更快,导致在内核与存储器速度间出现了一个性能缺口。越靠近内核内存速度越快,但容量也就越小。Cache的机制是基于位置原理设计的,在讲述Cache机制前先介绍一下位置原理。所谓位置原理,即假设如果一个存储器位置被引用,则其相同或相邻位置非常可能会很快又被引用。在一段时间内访问存储器的位置被指为时间位置,涉及相邻存储器的位置被指为空间位置。通过利用存储器访问位置原理,Cache缓存减少平均存储器访问时间。基于位置原理,在一小段时间内,通常一个程序从相同或相邻存储器位置重用数据。如果数据从一个慢速存储器映射到一个快速Cache存储器,在另一组数据替代前,尽可能经常访问Cache中的数据以提高数据访问效率。3.2C64x和C66x DSP之间的Cache区别对于使用过C64x内核的程序员来说,C66x内核Cache的概念与C64x内核中的相似,但也有很大不同。本节介绍C66x内核与C64x内核之间的Cache区别,主要有以下几点。1. 存储器尺寸和类型对于C66x器件,每个L1D和L1P在Cache之外实现SRAM。Cache的尺寸是用户配置的,可以被设置成4KB、8KB、16KB或32KB。可用的SRAM数量是器件相关的,并在器件特性数据手册中明确。而对于C64x器件,Cache被设计成尺寸为固定的16KB。C66x器件相对于C64x器件,L2的尺寸增加了。2. 写缓冲对于C66x器件,写缓冲的宽度增加到128位; 对于C64x器件,宽度是64位。3. Cache能力对于C66x器件,外部存储地址的Cache能力设置通过MAR位只影响L1D和L2 Cache缓存; 也就是说,到外部存储器地址的程序取指令program fetch总是被Cache缓存进来。不管Cache能力设置状况。这和C64x器件上的情况不一样,在C64x器件上Cache能力设置影响所有Cache,即L1P、L1D和L2。对于C66x器件,外部存储地址的Cache能力控制覆盖整个外部地址空间。对于C64x器件,外部存储地址的Cache能力控制只覆盖地址空间的一个子集。4. Snooping协议在C66x器件上的Snooping Cache一致性协议直接发送数据到L1D Cache和DMA。C64x器件通过invalid和writeback Cache Line来维持一致性。由于减少了由invalidate导致的Cache缺失开支,C66x Snooping机制更加有效。与C64x器件一样,Snoop协议在C66x器件中不维护L1P Cache和L2 SRAM之间的一致性,程序员负责维护其一致性。5. Cache一致性操作对于C66x器件,L2 Cache一致性操作总是操作在L1P和L1D,即使L2 Cache功能被禁用。这与C64x器件情况不同,其需要明确调用L1一致性操作。C66x器件支持一整套的区域和全局Range and GlobalL1D Cache一致性操作,而C64x器件只支持L1D区域invalidate和writebackinvalidate操作。在Cache尺寸上有改变,C66x器件在初始设置一个新尺寸前,自动writebackinvalidate Cache。而C64x器件需要执行一个完整的writebackinvalidate程序虽然这些是被一部分CSL函数处理的。对于C66x器件,L2 Cache不包括L1D和L1P,两者不相关。这意味着一个行从L2驱逐evict,不会导致相应的行在L1P和L1D被驱逐。不相关的优势在于: 由于程序取指令导致的L2中的行分配不会从L1D Cache驱逐数据; 由于数据访问导致L2中的行分配不会从L1P驱逐程序代码,这减少Cache缓存缺失的数量。以下介绍C66x Cache存储器结构概览、Cache基础知识并详细介绍各级Cache。3.3Cache存储器结构概览C66x DSP存储器由内部两级基于Cache的存储器和外部存储器组成。L1P和L1D都可以被配置成SRAM和Cache,Cache最大可以达到32KB。所有Cache和数据路径自动被Cache控制器管理,如图3.1所示。1级存储器通过核访问,不需要阻塞。2级存储器可以被配置,并可被分成L2 SRAM和Cache。外部存储器可以为几MB大小。
图3.1C66x DSP Cache概览
C6678器件上电配置如下:复位后L1P被配置为全为Cache,大小为32KB。复位后L1D被配置为全为Cache,大小为32KB。复位后L2全是SRAM,Cache的容量可以被配置为32KB、64KB、128KB、256KB或全为Cache。访问时间取决于接口和使用的存储器技术。3.4Cache基础知识通常, Cache可以分为直接映射Cachedirectmapped Caches和组相联Cache setassociative Caches两种类型。本节介绍Cache的一些基本知识。为了较好理解Cache机制,首先介绍几个Cache的基本概念。1 Cache LineCache行: Cache处理的最小单位。Cache Line的尺寸要比内存存取的数据尺寸要大,一个行的大小为一个行尺寸Line Size。例如,C66x内核可以访问单个字节,而L1P Cache行尺寸为32B,L1D Cache行尺寸为64B,L2 Cache行尺寸为128B。但是,如果发生一次读失效,则Cache会将整条Cache Line的数据读入。2 Line Frame行帧: Cache中用于存储Cache Line的位置,包含被Cache的数据1行、一个关联的Tag地址和这一行的状态信息。这一行的状态信息包括是否Valid有效、Dirty脏和LRU状态。3 Set集: Line Frame的一个集合。直接映射的Cache中一个Set包含一个Line Frame,n路组相联的Cache每个Set包含n个Line Frame。4 Tag标签: Cache中被Cache的物理地址的高位作为一个Tag存储在Line Frame中,在决定Cache是否命中的时候,Cache控制器会查询Tag。5 Valid有效: 当Cache中的一个Line Frame保存了从下一级存储器取的数据,那么这个Line Frame的状态就是Valid的,否则,这个Line Frame的状态就是无效的Valid = 0。6 Invalidate失效: 是将Cache中标记为Valid的Line Frame状态标记为无效的过程,受影响的Cache Line内容被废弃。为了维持数据一致性,与writeback组合成writebackinvalidate,先将标记为Dirty的行写回到保存有这个地址的下一级存储器,再标记该行为无效状态。7 Dirty脏和Clean干净: 当一个Cache Line是Valid并包含更新后的数据,但还未更新到下一层更低的内存,则在Line Frame的Dirty位标志该Cache Line为脏的。一个Valid的Cache Line与下一层更低的内存一致,则Line Frame的Dirty位标志该Cache Line是Clean的Dirty = 0。8 Hit命中和Miss缺失: 当请求的内存地址的数据在Cache中,那么Tag匹配并且相应的Valid有效,则称为Hit,数据直接从Cache中取给DSP。相反,如果请求的内存地址的数据不在Cache中,Tag不匹配或相应的Valid无效,则称为Miss。9 Victim BufferVictim缓冲: Cache中的一条Cache Line为新的Line腾出空间的过程称为驱逐Evict,被驱逐的Cache Line被称为VictimLine。当Victim Line是Dirty的时,为了保持数据一致性,数据必须写回到下一级存储器中。Victim Buffer保存Vitim直到它们被写回到下一级存储器中。10 Miss Pipelining缺失流水: 对连续的缺失进行流水操作,提高对缺失处理的效率,降低阻塞Stall周期。11 Touch: 对一个给定地址的存储器操作,被称为Touch那个地址。Touch也可以指的是读数组元素或存储器地址的其他范围,唯一目的是分配它们到一个特定级别Cache中。一个内核中心循环用作Touch一个范围的内存,是为了分配它到Cache中,经常被称为一个Touch循环。Touch一个数组是软件控制预取数据的一种形式。3.4.1直接映射CacheL1P Cache直接映射Cache的工作原理可以参照C66x L1P Cache。任何时候内核访问L2 SRAM或外部空间中的指令,指令都被调入L1P Cache。1. 读缺失如果一个程序从地址0020h取出,假设那个Cache是完全无效的,意味着Cache中没有Cache Line包含该数据的缓存,这就是一个读缺失。一个行帧的有效状态被Valid V位指示: Valid位为0表示相应的Cache Line是无效的,也就是说,不包含被Cache缓存的数据。当核请求读地址0020h, Cache控制器把这个地址分为三块Tag、Set和Offset,如图3.2所示。
图3.2地址分块
Set部分bits 13~5指示地址映射到哪一个Set 如果是直接映射Cache,一个Set等于一个行帧。对于地址0020h,Set部分检测为1。然后控制器检测Tag bits 31~14和Valid位。由于我们假设Valid位为0,控制器寄存器是一个缺失,也就是说被请求的地址没有包含在Cache中。一个缺失也意味着: 为了容纳请求地址的行,一个行帧会被分配。然后控制器从存储器取行0020h~0039h,并存数据到行帧1。地址的Tag部分存储在Tag RAM中,Valid位变成1用以指示该Set包含有效数据。取出的数据同时也发送给核,访问结束。一个地址的Tag部分之所以必须被存储,这是因为当地址0020h再次被访问时会更清楚该地址已经被Cache缓存。2. 读命中Cache控制器把地址分割为三个部分: Tag、Set和Offset,如图3.2所示。Set部分决定地址映射到哪一个Set; 存储的Tag部分用于与请求的地址Tag部分比较。这个比较是必要的,因为存储器中多个行映射同一Set,通过Tag可以判断出请求的地址是否映射到Cache中。如果访问地址4020h也映射到同一个Set,Tag部分会不同,因而访问会是一个缺失。如果地址0020h被访问,Tag比较为真且Valid位为1,那么控制器寄存器为一个命中,并发送Cache Line中的数据到核,该访问结束。3.4.2Cache缺失的类型在组相联被讨论之前,最好理解不同类型的Cache缺失。Cache最大的目的是减少平均存储器访问时间。从存储器到Cache取一个行帧的数据,对于每个缺失,都会有损失。因而,对于最常使用的Cache Line,在被其他行替换前,要尽可能多地重复使用。这样一来,初始损失影响最小且平均存储器访问时间变得最短。Cache使用相同行帧来存储冲突的Cache Line,替换一个行帧将导致从Cache中驱逐另一个行帧。如果后续驱逐的行帧又被访问,那么访问会缺失且这个行帧必须再次从低速存储器取出。因而,只要一个行帧还会被使用,应避免它被驱逐。1. 冲突和容量缺失一个Set对应的数据已经被Cache缓冲,随后同一个Set的其他存储器位置被访问,就会由于冲突导致驱逐,这个类型的缺失被称为冲突缺失。一个冲突缺失的产生是因为一个Cache Line在它被使用前因为冲突被驱逐,更深层次的原因可能是因为Cache容量被耗尽,从而导致冲突发生。如果Cache容量被耗尽,当缺失发生时,Cache中的所有行帧被分配,这就是一个容量缺失。如果一个数据组超过重用Cache容量,容量缺失发生。当容量耗尽,新行访问从数组开始逐步替代旧行。确认一个缺失的原因有助于选择相应措施避免缺失。冲突缺失意味着数据访问合乎Cache大小,但是Cache Line因为冲突被驱逐。在这种情况下,我们可能需要改变存储器布局,以便数据访问被分配到存储器中Cache没有冲突的地址中。或者,从硬件设计上,我们可以创建多个Set保持两个或更多行。因而,存储器的两个行映射到相同Set可以都被保持在Cache中,相互不驱逐。这就是组相联的Cache。为了避免容量缺失,需要减少一次操作数据的数量。2. 强制性缺失第三类缺失是强制性缺失或首次引用缺失。当数据第一次传入,在Cache中没有该数据的缓存,因而肯定发生该类型Cache缺失。与其他两种缺失不同,这种缺失不刻意避免,因而是强制的。3.4.3组相联Cache组相联Cache具有多路Cache以减少冲突缺失的可能性。C66x L1D Cache是一个2路组相联的Cache,具有4KB、8KB、16KB或32KB容量,并且Cache行尺寸为64字节。L1D Cache的特点在表3.1中描述。表3.2提供了L1D缺失阻塞特征。
表3.1L1D Cache特点
特征C66x DSPC64x DSP组织2路组相联2路组相联协议读分配Read Allocate, Writeback读分配Read Allocate, Writeback内核访问时间1周期1周期容量4KB、8KB、16KB或32KB16KB行尺寸64字节64字节替换策略最近经常使用LRU最近最少使用LRU写缓冲4 128位4 64位外部存储器容量可配置可配置
表3.2L1D缺失阻塞特征
参数L2类型0 WaitState, 2128bit Banks1 WaitState, 4128bit Banks
L2 SRAML2 CacheL2 SRAML2 Cache
单个读缺失10.512.512.514.52并行读缺失流水10.5 412.5 812.5 414.5 8M连续的读缺失流水10.5 3M-112.5 7M-112.5 3M-114.5 7M-1M连续的并行读缺失流水10.5 4M2-1 3M212.5 8M2-1 7M212.5 4M-114.5 8M2-1 7M2在读缺失时Victim缓冲清空破坏缺失流水最大11个周期阻塞破坏缺失流水最大11个周期阻塞破坏缺失流水最大10个周期阻塞破坏缺失流水最大10个周期阻塞
写缓冲流出速度2周期条目6周期条目2周期条目6周期条目
与直接映射Cache相比,2路组相联Cache的每个Set由两个行帧组成: 一个行帧在路0; 另一个行帧在路1。存储器中的一条Cache Line仍然映射一个Set,不过现在可以存入两个行帧中的任一条。从这个意义上讲,一个直接映射的Cache也可以被看成一个1路Cache。组相联的Cache架构如图3.3所示。与直接映射类似,除了两个Tag比较不一样组相联的Cache中多路都进行Tag比较,Cache命中和缺失的机理相似。
图3.3组相联Cache架构
1. 读缺失如果两路都为读缺失,数据首先从存储器被取出。LRULeast Recently Used位决定Cache行帧被分配在哪一路中。每个Set有一个LRU位,可以被认为是一个开关。如果LRU位是0,行帧在路0被分配; 如果LRU位是1,行帧在路1被分配。任何时候只要存在一个到该行帧的访问,LRU的状态位就被改变。当一路被访问,LRU位总是切换到相反的路,为的是保护最近使用的行帧不被驱逐。基于位置原理,最近最少使用原则LRU被用来在同一Set里选择一个行帧作为被驱逐的行,用于保存新的Cache数据。2. 写缺失L1D是一个读分配的Cache,意味着在读缺失时一个行帧被分配到Cache。在一个写缺失时,数据通过一个写缓冲被写到更低级存储器,不会因此而产生新的L1D Cache关系。写缓冲有4个条目entry,在C66x器件中每个entry是128位宽。3. 读命中如果在路0有一个读命中,该行帧的数据在路0被访问; 如果在路1有一个读命中,该行帧的数据在路1被访问。4. 写命中在一个写命中活动中,数据被写到Cache,但是不是立即传递到更低的存储器。这种类型的Cache被称为写回writeback Cache,因为数据被一个内核的写访问修改并且在之后被写回到存储器。为了写回被修改的数据,哪一行被核写回必须清楚。为了实现这个目的,每条Cache Line具有一个Dirty位和它相关。最初,Dirty位是0。只要核写到一个被Cache的行,相应的Dirty位被设置。因为读缺失冲突,当Dirty的行需要被驱逐,它会被写回到存储器。如果那一行没有被修改Clean Line,它的内容被丢弃。例如,假设行在Set 0,路0被内核写,LRU位指示在下一个缺失时路0将会被替换; 如果内核当前产生一个到存储器位置映射到Set 0的地址的读访问,当前的Dirty行首先写回到存储器,随后新数据被存储到这个行帧。一个写回可能被程序发起,通过发送一个写回命令到Cache控制器。3.4.4二级Cache如果在存储器尺寸和访问时间上,Cache和主存储器之间有较大差别,二级Cache被引进用于减少更多存储器访问数量。二级Cache基本操作方式与1级Cache相同; 然而, 2级Cache在容量上更大。1级和2级Cache相互作用如下: 一个地址在L1缺失就传给L2处理; L2使用相同的Valid位和Tag比较来决定被请求的地址是否在L2 Cache。L1命中直接从L1 Cache得到服务,并不需要牵涉L2 Cache。与L1P和L1D一样,L2存储空间可以被分成一个可寻址的内部存储器L2 SRAM和一个Cache L2 Cache部分。与L1 Cache只有读分配read allocate不一样,L2 Cache是读分配和写分配write allocate的Cache。L2 Cache只被用来Cache缓存外部存储器地址,然而,L1P和L1D被用于Cache缓存L2存储器和外部存储器地址。L2 Cache特征概述如表3.3所示。
表3.3L2 Cache特征
特征C66x DSPC64x DSP
组织方式4路组相联4路组相联协议读分配和写分配读分配和写分配写回写回容量32KB、64KB、128KB或256KB32KB、64KB、128KB或256KB行尺寸128B128B替换策略最近使用LRU最近最少使用LRU外部存储器容量可配置可配置
1. 读缺失和读命中考虑一个内核读请求的场景,即访问可被Cache缓存的外部存储器地址,而Cache在L1缺失可能是L1P或L1D。如果地址也在L2 Cache缺失,相应的行会引入L2 Cache。LRU位决定了哪路行帧被分配到其中。如果行帧包含Dirty数据,在新行被取出前,首先会写回到外部存储器如果这一行的数据也包含在L1D,在L2 Cache Line被发送给外部存储器前,首先会写回到L2。为保持Cache一致性,这个操作是需要的。最新分配的一行形成一个L1 Line并包含请求的地址,然后传送给L1。L1在其Cache存储器中存储该行,并最后发送请求的数据到内核。如果在L1中新行替换一个Dirty行,它的内容首先写回到L2。如果地址是一个L2命中,相应的行直接从L2传到L1 Cache。2. 写缺失和写命中如果一个核写请求到一个外部存储器地址在L1D中缺失,它将被通过写缓冲传送给L2。如果对于这个地址L2检测到一个缺失,相应的L2 Cache Line被从外部存储器取出,被用内核写操作修改并被存入分配的行帧中。LRU位决定哪路行帧用于分配给新数据。如果行帧包含Dirty数据,它会在新行取出前首先被写回到外部存储器。注意新行没有存储进L1D,因为它只是一个readallocate Cache。如果地址是一个L2命中,相应的L2 Cache Line直接更新为核写的数据。3. 外部存储地址Cache能力L2 SRAM地址总是Cache缓存进L1P和L1D,然而,默认状态下,外部存储地址在L1D和L2 Cache中,被分配为不可Cache缓存的。因此,Cache能力必须首先被用户明确使能。注意L1P Cache是不被配置影响的,并且总是Cache缓存外部存储器地址。如果地址是不可Cache缓存的,任何存储器访问数据访问或程序取无须分配行到L1D或L2 Cache。3.5L1P CacheC66x内核中L1P与L1D上电后默认全为Cache,与L1D Cache不同的是L1P Cache为直接映射Cache。本节描述L1P Cache的相关知识。3.5.1L1P存储器和CacheL1P存储器和Cache的目的就是最大化程序执行效率。L1P Cache的可配置性为系统设计提供了灵活性。L1P Cache的特点为: L1P Cache可配置成0KB、4KB、8KB和32KB,存储器保护可配置,Cache块和全局一致性操作可配置。L1P存储器支持最大128KB的RAM空间具体参见器件配置情况。L1P存储器不能被同一个核内的L1D、L1P和L2 Cache缓存。L1P只能被EDMA和IDMA写,不能被DSP存储写入。L1P可以被EDMA、IDMA和DSP访问读取。L1P存储器最大的等待状态为3周期,等待周期不能被软件配置,这是由具体器件决定的。L1P存储器等待状态通常为0个周期。为了在一个较高的时钟频率取程序代码并维持一个较大的系统空间,L1P Cache是很有必要的,并可以把部分或全部的L1P都作为Cache。从L1P存储器地址映射的最顶端开始,采用自顶向下的顺序,L1P把存储器转换为Cache。最高地址的L1P存储器首先被Cache缓存。用户可以通过寄存器控制L1P Cache的操作。表3.4列出了这些寄存器概要。
表3.4L1P Cache寄存器概要
地址缩略词寄存器描述
0184 0020hL1PCFGL1程序配置寄存器0184 0024hL1PCCL1程序Cache控制寄存器0184 4020hL1PIBARL1程序无效基址寄存器0184 4024hL1PIWCL1程序无效计数字寄存器0184 5028hL1PINVL1程序无效寄存器
3.5.2L1P Cache结构L1P Cache是直接映射的Cache,意味着系统中每个物理存储位置都在Cache中有一个可能归属的位置。当DSP想取一段代码,DSP首先要检查请求的地址是否在L1P Cache中。为了实现这个功能,DSP提供的32位地址被分割成三段Tag、Set和Offset,如图3.2所示。Offset占5b,是因为L1P行尺寸为32字节。Cache控制逻辑忽略地址的0~4位信息。如果被Cache缓存,Set域指示被Cache缓存的数据位于L1P Cache中行的地址。Set域的宽度主要取决于L1P被配置为Cache的大小。对于任何已经在这些地址被Cache缓存的数据,L1P用Set来查找,并检查Tag,如Valid标志位指示在Tag中地址是否代表Cache中的一个有效的地址。如果L1P读缺失,请求被发给L2控制器,数据从系统中的位置中被取出。L1P缺失可能会,也可能不会直接导致DSP阻塞Stall。L1P通常情况下不能被DSP写。替换规则: 在所有Cache配置中,L1P Cache都是直接映射的。这意味着每个系统存储位置在L1P Cache中有且只有一个对应位置。由于L1P直接映射,其替换策略为: 每个新的Cache Line替换之前被Cache的数据。L1P Cache结构允许在运行中更改L1P Cache的大小,以实现L1P模式改变操作。具体操作为向L1PCFG寄存器中L1PMODE域写入与L1P Cache大小相对应的模式设置,对照表如表3.5所示。
表3.5L1 Cache配置大小
L1PCFG中L1PMODE设置L1P Cache大小L1PCFG中L1PMODE设置L1P Cache大小
000b0KB001b4KB010b8KB011b16KB100b32KB101b110b最大的Cache对应32KB111b最大的Cache对应32KB
L1P Cache模式的范围取决于实际的L1P存储器的大小。例如,如果L1P存储器的真实大小为16KB,那么L1P Cache最大为16KBL1PMODE为111b对应最大的Cache。当程序发起一个Cache模式转换,L1P Cache使当前内容无效。这样可以保证在更改Cache Tag的说明时没有错误的命中发生。为保证正确的Cache缓存行为,使数据无效是必要的,但对于防止由于重新分配L1P RAM成为Cache而导致的数据丢失,还是不够的。为了安全转换L1P模式,应用程序必须遵循以下步骤,如表3.6所示。
表3.6L1P Cache模式切换准则
由 此 切 换到程序必须执行以下步骤没有或具有较少
L1P Cache更多的
L1P Cache1 DMA、IDMA或拷贝任何影响范围之外的L1P RAM数据如果不需要保存,就不用DMA
2 把想写入的模式写入L1PCFG寄存器的L1PMODE域
3 读回L1PCFG,这样使DSP暂停直到模式转换结束具有较多的
L1P Cache没有或具有较少L1P Cache1 把想写入的模式写入L1PCFG寄存器的L1PMODE域
2 读回L1PCFG,这样使DSP暂停直到模式转换结束
3.5.3L1P冻结模式对于应用层面,L1P Cache直接支持一种冻结模式。这种模式下允许应用避免DSP的数据访问破坏Cache中的程序代码。这种特征在中断上下文时十分有用。在冻结模式,L1P仍然支持命中访问,读命中从Cache返回数据。但是,在该模式,既不允许对新的读缺失分配Cache Line,也不允许现存的Cache Line内容被标志为invalid。L1PCC寄存器的OPER域控制L1P是正常工作还是被冻结。DSP可以向L1PCC的OPER域写001b使L1P进入冻结模式,向L1PCC的OPER区域写000b使L1P进入正常状态。L1P冻结模式Cache可以通过CSL函数被控制:
Cache_freezeL1p;
Cache_unfreezeL1p;
3.5.4程序启动的一致性操作1. 全局一致性操作在主要的事件如任务切换、L1P模式改变、存储器保护设置改变等活动中,全局一致性操作使L1P与系统同步。全局一致性操作可以在软件控制中使L1P Cache全局无效,通过向L1PINV寄存器中的1位写入1发起全局无效操作。2. 块一致性操作块一致性操作与全局一致性操作相似,但块一致性只应用于定义好的程序块。L1PIBAR和L1PIWC分别定义块的基址和字数32位。3.6L1D Cache如上一节所述,C66x内核中L1P与L1D上电后默认全为Cache,不同的是L1D Cache为两路组相联Cache。本节描述L1D Cache的相关知识。
3.6.1L1D存储器和CacheL1D存储器和Cache的目的就是最大化数据处理性能。L1D存储器和Cache可配置性为系统设计提供了灵活性。L1D存储器和Cache具有以下特征:L1D Cache可配置成0KB、4KB、8KB和32KB,具备存储器保护功能,可以进行Cache块和全局一致性操作。L1D存储器不能被同一个核内L1D、L1P和L2 Cache缓存。L1D被初始化成全是Cache。C66x L1D存储器和Cache结构允许转换一部分或全部L1D为一个readallocate、writeback、两路组相联Cache。3.6.2L1D Cache结构L1D Cache是一个两路组相联Cache,意味着系统中每个物理存储器位置在Cache中具有两个可能的映射位置。当DSP试图访问一片数据,L1D Cache必须检查请求的地址是否保留在L1D Cache任一路中。为此,DSP提供的32位地址被分割成6个域,如图3.4所示。
图3.4L1D数据访问地址结构
6位的Offset说明实际上L1D行尺寸为64字节。Cache控制逻辑忽略地址的0~5位Byte、Bank和Subline域。0~5位决定哪个Bank及Bank中哪个字节被访问,因而它们与Cache的Tag比较逻辑是无关的。Set域指示数据如果被Cache缓存,将会被保存的L1D Cache Line地址。Set域的宽度取决于用户配置L1D Cache的大小,如表3.5所示。与检查Valid位一样,使用Set域来查找并对任何已经从那个地址被Cache缓存的数据检查每一路的Tag域,Valid指示Tag中的地址是否实际代表一个保存在Cache中的有效地址。Tag域是地址的高位部分,确定数据元素的真实物理位置。Cache功能检查L1D Cache中两路保存的Tag。如果一个Tag匹配,在读操作时,相应的Valid位如果被设置,那么就是一个命中,数据缓存直接从L1D Cache中返回数据,否则,读为缺失。DSP也可以写数据到L1D。当DSP执行存储store操作,L1D执行与读操作类似的Tag比较操作。如果发现为一个有效的匹配,写操作就为一个命中,数据被直接写到L1D Cache位置。否则,写操作为一个缺失,并且数据在L1D写缓冲排队,这个缓冲被用于在写缺失时减少DSP阻塞周期。由于DSP不等待数据从写操作返回,因而不会在L2访问时阻塞。L1D Cache配置决定Set尺寸和Tag域,如表3.7所示。
表3.7L1D Cache配置大小
L1DCFG中L1DMODE设置L1D Cache大小X Bit位置描述000b0KBNAL1D全为RAM001b4KB1032 L1D Cache line010b8KB1164 L1D Cache line011b16KB12128 L1D Cache line100b32KB13256 L1D Cache line
101b110b保留,映射为32KB111b最大的Cache对应32KB
3.6.3L1D冻结模式对于应用的操作,L1D Cache直接支持冻结模式。这个模式允许实时应用在不同代码段执行时如中断处理程序限制从L1D被驱逐的数据数量。L1D冻结模式只影响L1D Cache。L1D RAM不会被冻结模式影响。在冻结模式,L1D Cache正常服务于读命中和写命中,稍微不同的是LRU位不被修改。读命中从Cache返回数据,写命中更新Cache Line中被Cache缓存的数据并且根据需要标记为Dirty; LRU位没有被更新。在冻结模式,当读缺失时,L1D Cache不再分配新Cache Line,也不会驱逐任何已经存在的Cache内容。写缺失在L1D写缓冲中被正常排队。在冻结模式,L1D Cache仍然正常响应从L2发起的Cache一致性命令snoopread、snoopwrite,与任何程序发起的Cache控制一样writeback、invalidate、writebackinvalidate和模式切换。L1D的冻结模式对L2是否分配Cache Line没有影响。同样地,L2的冻结模式对L1D是否分配Cache Line没有影响。L1DCC寄存器中的OPER域控制L1D冻结模式。通过写1到OPER域,DSP把L1D置为冻结模式; 通过写0到L1DCC寄存器OPER域,DSP恢复L1D为正常操作状态。L1DCC寄存器POPER域保存OPER域以前的值。L1DCC寄存器OPER域的值拷贝到L1DCC寄存器POPER域。这缓解了在被写之前读L1DCC寄存器的读开销周期为了保存OPER以前的值。当用户需要执行一个写操作到L1DCC寄存器,执行以下操作:1 L1DCC寄存器中OPER域的内容拷贝到POPER域;2 POPER域失去之前的值;3 OPER域根据DSP写L1DCC寄存器bit 0的值更新,因而,写L1DCC寄存器只修改了L1DCC的OPER域。为了确保L1PCC寄存器更新了,软件必须在执行一个写操作到L1PCC寄存器之后紧跟一个读L1PCC寄存器的操作,这确保请求的模式生效。程序不能用一个写操作直接修改POPER域。3.6.4程序发起的Cache一致性操作C66x L1D Cache支持程序发起的Cache一致性操作,这些操作或操作在块地址,或操作在整个L1D Cache。以下Cache一致性操作被支持。1 失效Invalidate: 有效的Cache Line被设置成无效,受影响的Cache Line被废弃。2 写回Writeback: 所有Dirty的Cache Line写回到更低级别的存储器。3 写回失效WritebackInvalidate: 写回操作之后紧接着是失效操作,只有Dirty的Cache Line被写回到更低级别的存储器,但是所有行被失效。3.7L2 Cache通常,L2被配置为全是SRAM,可以用于做数据缓冲。不过,L2也可以配置为Cache,与L1P和L1D Cache不同的是,L2 Cache为read allocate和write allocate的4路组相联Cache。3.7.1L2存储器和Cache在一个使用C66x内核的器件中,L2存储器和Cache提供灵活的配置方式,为系统设计提供了灵活性。L2存储器和Cache具有以下特征:L2 Cache可配置成32KB、64KB、128KB、256KB、512KB或1MB最大值由器件配置决定,具备存储器保护功能,支持Cache块和全局一致性操作。C66x内核默认配置映射所有L2存储器全为RAM。L2存储器控制器支持容量为32KB、64KB、128KB、256KB、512KB或1MB的Cache,为4路组相联Cache。L2 Cache通过一些寄存器来被控制,如表3.8所示。
表3.8L2 Cache寄存器概要
地址缩略词寄存器描述0184 0000hL2CFGL2配置寄存器0184 4000hL2WBARL2 Writeback基址寄存器0184 4004hL2WWCL2 Writeback字word数寄存器0184 4010hL2WIBARL2 WritebackInvalidate基址寄存器0184 4014hL2WIWCL2 WritebackInvalidate字word数寄存器0184 4018hL2IBARL2 Invalidate基址寄存器0184 401ChL2IWCL2 Invalidate字word数寄存器0184 5000hL2WBL2 Writeback寄存器0184 5004hL2WBINVL2 WritebackInvalidate寄存器0184 5008hL2INVL2 Invalidate寄存器MARn存储器属性寄存器
3.7.2L2 Cache结构L2 Cache是一个读和写分配read allocate和write allocate的4路组相联Cache。为了跟踪L2 Cache Line的状态,L2 Cache控制器包含一个4路Tag RAM。L2 Tag中的地址结构是一个Cache和RAM分割的函数,由L2CFG寄存器L2MODE域控制。L2数据访问地址结构如图3.5所示。
图3.5L2数据访问地址结构
7位的Offset说明L2行尺寸实际上为128字节。Cache控制逻辑忽略地址的这部分域。数据如果被Cache缓存,Set域指示数据将会存进每路中L2 Cache Line的地址。Set域的宽度取决于用户配置L2为Cache的大小,如表3.9所示。L2控制器用Set域查找,并检查任何已经被Cache缓存的数据每一路的Tag域。同时控制器检查Valid位,以确认Cache Line的内容对Tag比较是否有效。
表3.9L2 Cache配置大小
L2CFG中L2MODE设置L2 Cache大小x Bit位置描述000b0KBNAL2全为RAM001b32KB1264 L2 Cache Line010b64KB13128 L2 Cache Line011b128KB14256 L2 Cache Line011b256KB15512 L2 Cache Line100b512KB161024 L2 Cache Line110b1024KB172048 L2 Cache Line111b最大的Cache对应1024KB
注意: 总的来说,一个大的L2MODE值指定一个大的Cache尺寸,最大为器件有效的L2存储器容量。Tag域是指示Cache Line的物理位置地址的高位部分。Cache对一个给定的地址与存储的所有4路的Tag域进行比较。如果任何一个Tag匹配成功并且Cache数据是Valid,那么访问就为命中,数据元素直接从L2 Cache读或直接写到L2 Cache位置。否则,就是一个缺失。当L2从系统存储器位置取完整的行时,请求者保持阻塞。L2 Cache的替换机制为典型的LRU机制。3.7.3L2冻结模式L2 Cache提供一个冻结模式。L2 Cache的内容在这种模式被冻结也就是说,在正常操作时不会更新。L2冻结模式允许一个实时应用在不同代码段期间如中断服务程序限制从L2驱逐数据的数量。用L2CFG寄存器L2CC域来设置这种模式。冻结模式只影响L2 Cache的操作。同样地,L1的冻结模式不影响L2 Cache。在冻结模式,L2 Cache正常响应读和写命中。L2直接发送读和写缺失到外部存储器,就像L2 Cache不存在。当冻结时,L2不分配新的Cache Line。在冻结模式,只可能由程序发起的Cache一致性操作从L2驱逐Cache Line。3.7.4程序发起的Cache一致性操作L2存储器架构支持多种一致性操作,分成两种基本类型: 到一个指定地址范围的块操作和操作一个或更多Cache的全部内容的全局操作。下面列出了存储器支持的Cache一致性操作。1 失效Invalidate: 有效的Cache Line被设置成无效,受影响的Cache Line内容被废弃。2 写回Writeback: Valid和Dirty的Cache Line内容被写到更低级别存储器中。3 写回失效Writebackinvalidate: 写回操作紧跟一个失效,只有受影响的Cache Line内容被写回到更低级别的存储器,但是所有行都失效了。1. 全局一致性操作全局一致性操作在整个L2 Cache上执行。一些全局一致性操作也会影响L1 Cache。表3.10列出了所有L2全局一致性命令和它们在每个Cache上执行的操作
表3.10全局一致性操作
Cache操作使用的寄存器L1P影响L1D影响L2影响L2写回L2WB没影响所有更新的数据写回L2或外部存储器,但L1D中Cache关系保持有效所有更新的数据写回外部存储器,但L2中Cache关系保持有效L2写回并失效L2WBINV所有在L1P的行失效所有更新的数据写回L2或外部存储器,所有L1D中的行无效所有更新的数据写回外部存储器,所有L2中的行无效L2失效L2INV所有在L1P的行失效所有L1D中的行无效,更新的数据被废弃所有L2中的行无效,更新的数据被废弃
程序发起全局Cache一致性操作通过写1到每个L2WB、L2WBINV和L2INV寄存器中相应的寄存器位。操作完成后,程序可以查询相应的寄存器位以决定什么时候命令结束。以下给出如何使用L2WBINV寄存器的示例。
L2WBINV = 1; * Write back and Invalidate anything held in cache. *
* ---------------------------------------------------------------- *
* OPTIONAL: Spin waiting for operation to complete. *
* ---------------------------------------------------------------- *
while L2WBINV & 1 != 0
;
对于这些命令的完成,硬件实现查询,不需要软件参与。然而,当全局命令正在进行时,硬件可能使程序阻塞。不考虑L2冻结的状态,全局一致性操作正常工作。而且,全局一致性操作不会改变L2冻结的状态。2. 块一致性操作块一致性操作具有与全局一致性类似的功能,但是块一致性操作只能应用于一个限定的数据块。块通过相关寄存器中的基地址和字长度来确定。表3.11为块Cache操作。
表3.11块Cache操作
Cache操作使用的寄存器L1P影响L1D影响L2影响
L2写回L2WBAR
L2WWC没影响所有更新的数据写回L2或外部存储器,但L1D中保持有效所有更新的数据写回外部存储器,但L2中Cache关系保持有效L2写回并失效L2WIBAR
L2WIWC所有范围内的L1P行失效所有更新的数据写回L2或外部存储器,所有范围内的行在L1D Cache中失效所有更新的数据写回外部存储器,所有范围内的行在L2中失效L2失效L2IBAR
L2IWC所有范围内的L1P行失效所有地址范围内的行在L1D中失效,更新的数据被废弃所有范围内的行在L2中的Cache关系失效,更新的数据被废弃
程序通过写一个字的地址到基地址寄存器发起块Cache操作,然后写一个字的计数到计数寄存器写1到WC表示4个字节。如有必要,C66x内核需严格实施以下准则:1 每次只有一个程序发起的一致性操作正在进行中。2 当另一个块或全局Cache一致性操作在进行中,写到L2XXBAR或L2XXWC导致阻塞。L2XXBARL2XXWC用于建立块Cache操作机制,允许用户指定范围,最小颗粒度为字。然而,存储器系统操作粒度以Cache Line为单位,因而,所有覆盖范围的行被执行。对于C66x DSP,推荐程序等待块一致性操作完成后再继续。为了执行一个块一致性操作,执行以下命令:1 写起始地址到L2XXBAR寄存器。首先,写一个非0值到L2XXBAR寄存器设置了下一个Cache一致性操作的基地址。2 写字计数到L2XXWC寄存器。写一个非0值到L2XXWC发起这个操作。在一个Cache操作之后或正在操作中,程序必须依赖L2XXBAR的内容。最好的方式是: 程序应该总是先写一个新值到L2XXBAR,然后再写L2XXWC。3 通过以下途径之一等待完成:①执行一个MFENCE指令推荐; ②查询L2XXWC寄存器直到字计数域读为0。MFENCE指令对于C66x DSP是新的,它使DSP阻塞直到所有未完成的存储器操作完成。当一个块Cache操作正在进行中,读L2XXWC返回一个非0的值,当它完成返回为0。无论L2是否为冻结状态,块一致性操作正确地工作。3.7.5Cache能力控制在一些应用中,访问一些指定的地址可能需要从它们物理位置读如FPGA中的状态寄存器、多核共享的控制信号等。L2控制器提供寄存器组,用来控制特定范围内的存储器是否可以Cache缓存、是否一个或更多请求者实际被允许访问这些范围。这些寄存器指的是MAR存储器属性寄存器寄存器。注意: 使用C语言中volatile关键字不能保护一个变量不被Cache缓存。如果一个应用使用一个周期性被外部硬件更新的存储器位置,为了在C代码中保护这个操作,需要遵循以下两步:1 使用volatile关键字阻止代码产生工具不正确的优化变量。2 用户必须设置覆盖范围包含该变量的MAR寄存器,以阻止Cache缓存功能。1. MAR功能每个MAR寄存器为2b: 许可拷贝Permit Copies,PC和外部可预取Prefetchable Externally,PFX。每个MAR寄存器的PC位控制Cache功能是否可以保持被影响地址范围的一份拷贝。如果PC = 1,影响的地址范围可以被Cache缓存; 如果PC = 0,影响的地址范围不可以被Cache缓存。每个MAR寄存器的PFX位用来向XMC表达一个给定地址范围是否可以预取。如果PFX = 1,影响的地址范围是可以预取的。如果PFX = 0,影响的地址范围是不可以预取的。2. 特殊MAR寄存器MAR0~MAR15代表C66x内核中保留的地址范围,并按如下处置:1 MAR0是一个只读寄存器。MAR0的PC总是被读为1。2 MAR1~MAR11与内部和外部配置地址空间相对应。因而,这些寄存器是只读的,并且PC域总是被读为0。3 MAR12~MAR15与MSMC存储器对应。这些是只读寄存器,PC总是读为1。这使得MSMC存储器通过其最初地址范围访问总是在L1D内可被Cache缓存。MAR寄存器定义如图3.6所示,存储器属性寄存器MARn域描述如表3.12所示。
图3.6MAR寄存器结构
说明: R表示只读; W表示只写; n表示复位后的值; SRW表示只被管理者读写。
表3.12存储器属性寄存器MARn域描述
位域值描述
31~4Reserved0Reserved3PFX0存储器范围不可以预取1存储器范围可以预取2~1Reserved0Reserved0PC0存储器范围不可以Cache缓存1存储器范围可以Cache缓存
存储器属性寄存器MAR地址对照表见附录B,其中列出了各MAR寄存器地址、描述和定义属性的地址范围。MAR寄存器只能被管理代码修改。3.8使用Cache如何正确地使用Cache是提升内核综合处理能力的一个重要因素。本节描述如何正确配置Cache。3.8.1配置L1 Cache器件加载后的状态取决于特定的C66x器件,器件可能加载成全为Cache、全为SRAM或为两者混合。对于C6678,L1P加载后全为Cache。在程序代码中执行相应的CSL命令Cache_L1psetSize、Cache_L1dsetSize可以改变L1P和L1D Cache尺寸。此外,在连接命令文件Linker Command File中,如果存储器被用作SRAM则其必须被指定。因为Cache不能被连接器用作代码或数据放置,所有连接命令文件中的段必须连接到SRAM或外部存储器。3.8.2配置L2 Cache在加载时,L2 Cache被禁用,所有L2被配置为SRAM可寻址的内部空间。如果SYSBIOS被使用,L2 Cache功能被自动使能; 否则,在程序代码中L2 Cache可以通过使用相应的CSL命令Cache_L2setSize使能。此外,在连接命令文件中,如果存储器被用作SRAM,则其必须被指定。因为Cache不能通过连接器被用作代码或数据位置,所有连接命令文件的段必须连接到SRAM或外部存储器。对于L1D和L2,用户可以通过控制外部存储器以决定地址是否被Cache缓存或不被Cache缓存。每个16MB外部存储器地址空间由一个MAR寄存器控制MAR寄存器值为0表示不被Cache缓存,值为1表示可被Cache缓存。例如,为使能外部存储器Cache范围8000 0000h~80FF FFFFh,可以使用CSL函数CHE_enableCachingCache_MAR128设置MAR128为1PC=1。外部存储器空间MAR位被设置后,通过核的新地址访问会被Cache缓存。如果它被设为不被Cache缓存,访问数据会简单地从外部存储器发送给核,而不会被存在L1D或L2 Cache。注意: 程序取L1P总是被Cache缓存的,无论MAR的设置如何。在加载时,外部存储地址空间的Cache功能是被禁用的。以下描述假设L2存储器容量为2048KB,并且L1P及L1D都是Cache。对于具有不同的L2尺寸的C66x器件,具体参数需查相应的器件数据手册。连接命令文件配置1792KB SRAM和256KB Cache,如示例3.1所示。请求的CSL命令顺序使能外部存储器位置的Cache并使能L2 Cache,如示例3.2所示。通过设置相应的MAR位,第一个命令允许Cache缓存第一个外部存储空间的16MB。最后,L2 Cache尺寸被设置为256KB。图3.7显示对于有2048KB L2存储器的C66x器件,所有Cache配置的可能情况。在其他C66x器件中配置略有不同。
图3.7L2存储器配置Cache情况
注意: 当L2 Cache尺寸增大,高位存储器地址被占用。L2 Cache尺寸设置如示例3.1和示例3.2所示。注意: 不要在MEMORY指示中定义将被用作或加载起来作为Cache的存储器。对于连接器放置代码或数据的位置,存储器是无效的。如果要使用L1D SRAM、L1P SRAM,首先通过减少Cache尺寸使RAM是可用的。数据或代码必须连接到L2 SRAM或外部存储器,然后在运行中被拷贝到L1。【示例3.1】C66x连接命令文件。
MEMORY
{
L2SRAM: origin = 00800000h length = 001C0000h
CE0: origin = 80000000h length = 01000000h
}
SECTIONS
{
.external CE0
}
End of示例
【示例3.2】C66x使能Cache的CSL命令顺序。
#include
#include
...
Cache_enableCachingCache_CE00;
Cache_setL2SizeCache_256KCache;
End of示例
3.9数据一致性通常,如果多个设备如内核或外围设备共享可被Cache缓存的存储器区域,Cache和存储器可以变得不一致。了解数据一致性产生的机理,有助于正确使用Cache。本节介绍数据一致性的相关知识。考虑如图3.8所示的系统,以下描述步骤1到3与图对应。假设内核访问一个存储器位置,这导致其后该存储器相应的行被分配在Cache中1。随后,外围设备写数据到同一物理位置,这些数据打算被用于内核读取和处理2。然而,因为这个存储器的值保留在Cache中,存储器访问会命中Cache,内核从Cache中读旧数据而不是从物理位置中读新数据3。如果核写数据到被Cache缓存的存储器位置,同时该数据要被外围设备读,相似的问题出现了,外围设备读的是物理位置的旧数据而不是Cache中的新数据。这些情况下,Cache和存储器被称为不一致。
图3.8Cache一致性问题
如果存在以下情况,需要考虑一致性问题:1 多个请求者CORE数据通道、CORE取指令通道、外围设备、DMA控制器、其他外部实体共享一个存储器区域用于数据交换;2 这个存储器区域可以被至少一个设备Cache缓存;3 该区域中的一个存储器位置已经被Cache缓存;4 这个存储器位置被修改被任何设备。因此,如果一个存储器位置被分享、被Cache缓存,并被修改,这就存在Cache一致性问题。通过基于snoop命令的一种硬件Cache一致性协议,对于内核访问和EDMAIDMA访问,C66x DSPs自动保持Cache一致性。在一个DMA读和写访问时,一致性机制被激活。当一个DMA读一个被Cache缓存的L2存储器位置,数据直接从L1D Cache传到DMA,不需要被L2 SRAM更新。在一个DMA写,数据传送到L1D Cache并在L2 SRAM中更新。在以下情况中,需要靠编程人员来维护Cache一致性:1 DMA或其他外部实体写数据或代码到外部存储器,然后被内核读;2 内核写数据到外部存储器,然后被DMA或其他外部实体读;3 DMA写代码到L2 SRAM,然后被内核执行这种情况在C621xC671x和C64x DSPs硬件协议中被支持,但在C66x DSPs中不被支持;4 内核写代码到L2 SRAM或外部存储器,然后被该内核执行。为了这个目的,Cache控制器提供多种命令允许手动保持Cache一致性。3.9.1Snoop一致性协议Cache控制器使用基于Snoop的协议来维持L1D Cache和L2 SRAM之间的DMA访问一致性。通常,snooping是由更低级存储器发起的一个Cache操作,用来检查请求的地址是否在更高级的存储器中被Cache缓存valid,如果是,则相应的操作被触发。C66x Cache控制器支持以下snoop命令: L1D SnoopRead和L1D SnoopWrite。1. DMA访问L2 SRAM的Cache一致性协议为了说明snooping,假设一个外围设备通过DMA写数据到一个分配在L2SRAM的输入缓冲中。然后内核读取、处理、输出缓存该数据,数据最终通过DMA发送到其他外围设备。一个DMA写的过程如图3.9所示,并按如下步骤执行。
图3.9DMA写访问L2一致性问题
1 外围设备请求一个写访问到L2 SRAM的一行,该行映射到L1D的set 0。2 L2 Cache控制器检查其L1D tag RAM的本地拷贝,并确定刚刚被请求的行是否被L1D Cache缓存通过检查Valid位和Tag位。如果该行没有被L1D Cache缓存,不需要进一步的行动,数据被写入存储器。3 如果该行在L1D被Cache缓存,L2控制器更新在L2 SRAM的数据,并通过执行一个snoopwrite命令直接更新L1D Cache。注意Dirty位不影响这个操作。一个DMA读的过程如图3.10所示,并按如下步骤执行。1 内核写结果到输出缓冲。假设输出缓冲被预先分配在L1D。因为缓冲是被Cache缓存的,只有被Cache缓存的拷贝数据更新,而不是在L2 SRAM中的数据更新。2 当外围设备执行一个DMA读请求到L2 SRAM中的存储器位置,控制器检查以决定包含请求存储器位置的行是否被L1D Cache缓存。在这个例子中,我们已经假设它是被Cache缓存的。然而,如果它没有被Cache缓存,不需要进一步的操作发生,且外围设备会完成读访问。3 如果该行被Cache缓存,L2控制器发送一个snoopread命令给L1D。snoop首先检查以确定相应的行是否为Dirty。如果不是,外围设备允许完成读访问。4 如果Dirty位被设置,snoopread导致数据被直接传给DMA,无须把它写到L2 SRAM。这正是这个例子的情况,因为我们假设内核已经把数据写到输出缓冲了。
图3.10DMA读访问L2一致性问题
2. L2 SRAM双缓冲例子假设数据从一个外围设备读入、处理并写到另一个外围设备,这是一个典型的信号处理应用场景,数据流如图3.11所示。当内核正在对一对缓冲如InBuffA和OutBuffA的数据进行处理,外围设备使用另外一对缓冲InBuffB和OutBuffB正在写、读数据,这样DMA数据传输可以与核处理并行执行。示例中,假设InBuffA已经被外围设备填充,流程如下。1 当内核正在处理InBuffA中的数据,InBuffB正在被填充。InBuffA的行被分配到L1D。数据正在被内核处理,并被通过写缓冲写到OutBuffA 注意L1D只是readallocate的。2 当外围设备正在用新数据填充InBuffA,第二个外围设备正从OutBuffA读,并且内核正在处理InBuffB。对于InBuffA,L2 Cache控制器通过snoopwrites自动向前传输数据到L1D。对于OutBuffA,由于没有被L1D Cache缓存,没有必要进行snoop操作。3 缓冲又被交换,一直下去。对每个Cache缺失,为了得到最高的回报对被Cache缓存的数据而言,使L2 SRAM缓冲中放入多条L1D Cache Line可能是有益的。伪码如示例3.3所示,显示一个双缓冲如何设计实现。
图3.11DMA读、写访问L2一致性问题
【示例3.3】L2 SRAM DMA双缓冲代码。
for I=0; i OutBuffA Processing *
* ----------------------------------------------------*
processInBuffA, OutBuffA, BUFSIZE;
* -----------------------------------------------------*
*InBuffB - OutBuffB Processing *
* -----------------------------------------------------*
processInBuffB, OutBuffB, BUFSIZE;
}
End of 示例
3.9.2在外部存储器和Cache之间维持一致性
图3.12DMA读、写访问外部存储器一致性问题
考虑相同的双缓冲情景,但是缓冲位于外部存储器。因为Cache控制器在这种情况下不会自动维持一致性,程序员需要考虑一致性的问题。内核从外围设备读取数据并进行处理,之后通过DMA写数据到另外一个外围设备。但是现在数据传输通过L2 Cache,如图3.12所示。假设传输已经发生了,InBuff和OutBuff都被Cache缓存进L2 Cache,并且被Cache缓存进L1D。更进一步假设内核已经完成对InBuffB的处理,结果填充了OutBuffB,并正要开始处理InBuffA的行,即将开始引入新数据传输到InBuffB,同时OutBuffB中的结果也要传到外围设备。为了维持一致性,在DMA传输开始前,所有映射外部存储器输入缓冲的L1D和L2 Cache的行需要被invalidate。采用这个方法,当下次从外部存储器输入缓冲读数据时,内核会重新分配这些行。相似地,在OutBuffB被传输给外围设备前,数据首先必须从L1D和L2 Cache被写回到外部存储器。通过执行一个writeback操作,数据写回操作就被执行了。这是必要的,内核写数据只写到OutBuffB存储器位置的Cache缓存备份中,而数据可能还保存在L1D和L2 Cache中。CSLChip Support Library提供一组程序用于发起需要的Cache一致性操作。外部存储器中缓冲的起始地址和字节数需要被指定:
Cache_invL2InBuffB, BUFSIZE, Cache_WAIT;
Cache_wbL2OutBuffB, BUFSIZE, Cache_WAIT;
如果Cache_WAIT被使用,程序等待直到操作完成,这是推荐的做法。如果Cache_NOWAIT被使用,程序发起操作并立即返回。这允许内核继续执行程序,同时一致性操作在后台执行。然而,需要小心,必须确保内核没有访问Cache控制器正在操作的地址。因为这可能导致非预期的结果。为了确保一致性操作执行完,程序Cache_wait可以在DMA传输被发起之前使用。示例3.4中的伪码准确展示了Cache一致性调用和DMA传输必须发生的顺序。【示例3.4】外部存储器DMA双缓冲代码。
for i=0; i OutBuffA Processing *
* -----------------------------------------------------*
Cache_InvL2InBuffB, BUFSIZE, Cache_WAIT;
Cache_wbL2OutBuffB, BUFSIZE, Cache_WAIT;
processInBuffA, OutBuffA, BUFSIZE;
* -----------------------------------------------------*
*InBuffB - OutBuffB Processing *
* -----------------------------------------------------*
Cache_InvL2InBuffA, BUFSIZE, Cache_WAIT;
Cache_wbL2OutBuffA, BUFSIZE, Cache_WAIT;
processInBuffB, OutBuffB, BUFSIZE;
}
End of 示例
在一致性操作之外,所有DMA缓冲是L2 Cache Line对齐的,而且是Cache Line大小的整数倍。可以按照如下操作实现:
#pragma DATA_ALIGNInBuffA, Cache_L2_LINESIZE
#pragma DATA_ALIGNInBuffB, Cache_L2_LINESIZE
#pragma DATA_ALIGNOutBuffA,Cache_L2_LINESIZE
#pragma DATA_ALIGNOutBuffB,Cache_L2_LINESIZE
unsigned char InBuffA [N*Cache_L2_LINESIZE];
unsigned char OutBuffA[N*Cache_L2_LINESIZE];
unsigned char InBuffB [N*Cache_L2_LINESIZE];
unsigned char OutBuffB[N*Cache_L2_LINESIZE];
或者, CSL宏Cache_ROUND_TO_LINESIZECache, element count, element size可以被用来自动向上取整对齐队列到下一个Cache Line尺寸倍数的位置。第一个参数为Cache的类型,可以为L1D、L1P或L2。数组定义可以看起来如下:
unsigned char InBuffA [Cache_ROUND_TO_LINESIZEL2, N, sizeofunsigned char];
unsigned char OutBuffA[Cache_ROUND_TO_LINESIZEL2, N, sizeofunsigned char];
unsigned char InBuffB [Cache_ROUND_TO_LINESIZEL2, N, sizeofunsigned char];
unsigned char OutBuffB[Cache_ROUND_TO_LINESIZEL2, N, sizeofunsigned char];
3.9.3对L2 Cache一致性操作使用指导表3.13为C66x器件可用的L2 Cache一致性操作概览。注意这些操作总是操作在L1P和L1D上,即使L2 Cache被禁用。表3.13诠释如下。1 首先,Cache控制器操作在L1P和L1D上;2 然后,一致性操作在L2 Cache上被执行。
表3.13L2 Cache一致性概览
范围一致性操作CSL命令L2 Cache上的操作L1D Cache上的操作L1P Cache上的操作
有效范围Invalidate L2Cache_invL2start address, byte count, wait所有在范围内的行invalidate 任何Dirty数据被忽略所有在范围内的行invalidate 任何Dirty数据被忽略所有在范围内的行invalidateWriteback L2Cache_wbL2start address, byte count, wait在范围内的Dirty行写回,所有行保持valid在范围内的Dirty行写回,所有行保持valid无WritebackInvalidateL2Cache_wbInvL2start address, byte count, wait在范围内的Dirty行写回。所有范围内的行invalidate在范围内的Dirty行写回。所有范围内的行invalidate所有在范围内的行invalidate
所有L2 CacheWriteback All L2Cache_wbAllL2wait所有L2中的Dirty行写回。所有行保持有效所有范围内的行invalidate,所有L1D的Dirty行写回。所有行保持valid,L1D snoopinvalidate无Writeback
Invalidate
All L2Cache_wbInvAllL2 wait所有L2中的Dirty行被写回。所有L2的行invalidate所有在L1D中的Dirty行被写回。所有在L1D的行invalidate所有在L1P的行invalidate
注意: 一个行被Cache缓存进L1P或L1D,未必被Cache缓存进L2。一个行可能被从L2驱逐,不一定被从L1P或L1D驱逐。重要提示: 尽管起始地址和字节计数被指定,Cache控制器总是操作在整个行上。因而,为了维持一致性,数组必须是:1 L2 Cache Line倍数大小;2 在L2 Cache Line分界处对齐。一条L2 Cache Line长128字节。Cache控制器操作在所有被指定地址范围涉及到的行上。注意最大字节数可以被指定为465535字节在一些C66x器件上最大为4 65408字节,参考器件手册,也就是说,一个L2 Cache操作可以操作最多256KB。如果被操作的外部存储器缓存更大,多个Cache操作必须被执行。如果核与DMA或其他外部实体分享一个可Cache缓存的外部存储空间区域,才需要用户发起L2 Cache一致性操作。也就是说,在以下场景需要一致性操作,当内核读被DMA写的数据或DMA读被内核写的数据时,最安全的规则就是,在任何DMA传输对外部存储器读或写之前,执行一个WritebackInvalidate All。然而,这种做法的缺点是,可能需要更多的Cache Line被操作,而导致更大的开销。一个精准的方法更加有效,首先,它只需要操作在那些真实包含共享缓冲的Cache Line上; 其次,以下三种场景可以被区别对待,如表3.14所示。
表3.14L2 Cache一致性操作
场景需要的一致性操作DMAOther读的数据被内核写在DMAOther开始读之前Writeback L2DMAOther写的数据代码将被内核读在DMAOther开始写之前Invalidate L2DMAOther修改被内核写的数据之后又将被内核读回在DMAOther开始写之前WritebackInvalidate L2
在场景3,DMA可能修改被核写的数据且数据被内核读回。例如,内核在一个外围设备写到缓冲前初始化存储器如把它清0。在DMA开始之前,被核写的数据需要被传到外部存储器并且缓冲必须被Invalidate。3.9.4对L1 Cache一致性操作使用指导表3.15和表3.16显示C66x器件可用的L1 Cache一致性操作概览。
表3.15L1D Cache一致性操作
范围一致性操作CSL命令L1D Cache上的操作
有效范围
Invalidate L1DCache_invL1d start address, byte count,wait所有范围内的行invalidate 任何Dirty数据被忽略Writeback L1DCache_wbL1d start address, byte count,wait范围内的Dirty行被写回。所有行保持validWriteback Invalidate L1DCache_wbInvL1d start address, bytecount, wait范围内的Dirty行写回。所有范围内的行invalidate
所有L1D Cache
Writeback All L1DCache_wbAllL1d wait所有在L1D的Dirty行被写回。所有行保持validWriteback Invalidate All L1DCache_wbInvAllL1d wait所有在L1D的Dirty行被写回。所有行invalidate
表3.16列出了L1P Cache一致性操作。
表3.16L1P Cache一致性操作
范围一致性操作CSL命令L1D Cache上的操作有效范围Invalidate L1PCache_invL1pstart address, byte count, wait所有范围内的行invalidate所有L1P CacheInvalidate All L1PCache_wbInvAllL1p wait所有L1P的行invalidate
注意: 尽管一个起始地址和一个字节计数被指定,Cache控制器操作总是在整个行上。因而,为维护一致性的目的,数组必须是:1 L1D Cache Line大小的倍数;2 对齐L1D Cache Line分界线。一个L1D Cache Line是64字节。Cache控制器操作在所有指定地址范围涉及到的行上。注意最大字节数可以被指定为465535。表3.17中列出了Cache一致性操作必须被执行的场景。
表3.17需要L1一致性操作的场景
场景需要的一致性操作DMAOther写代码到L2 SRAM将要被内核执行在内核开始执行前Invalidate L1P内核修改在L2 SRAM或外部存储器的代码,该代码将被内核执行在内核开始执行前Invalidate L1P和WritebackInvalidate L1D
3.10片上Debug支持C66x DSPs提供片上Debug功能用于Debug Cache一致性问题。C66x存储器系统允许仿真直接访问个别Cache并报告Cache状态信息Valid、Dirty、LRU位。用户可以通过CCS IDE中Memory窗口的显示功能,获得Debug能力。如果怀疑出现Cache一致性问题,可以遵循以下步骤: 首先,确保排除任何不可预测的、影响内核访问一致性的操作,这需要先排除除了Cache一致性以外的其他原因。其次,确保缓冲对齐L2 Cache Line边界以减少虚假地址False Addresses。为了达到这个目的,存储器窗口提供可视的Cache Line边界标记,帮助用户很容易确定是否对齐。下一步,确保正确使用Cache一致性操作,如下:1 在完成invalidate一致性操作之后暂停内核执行,但是必须在第一次DMA写访问之前。2 核实此刻缓冲中没有行是Dirty的。为了检查该信息,用户可以使能存储器分析功能通过属性窗口,任何Dirty行会被显示成醒目的字体格式。3 继续内核执行。4 在第一次内核读之前再次暂停内核。5 确定缓冲仍然是invalidate并且包含期望的新数据。如果存在问题或数据被Cache缓存,用户可以使用Cache旁路复选框去观察在外部存储器中的数据内容。3.11在运行中改变Cache配置3.11.1禁用外部存储器Cache功能
在Cache功能被使能后,通常是不需要禁用外部存储器Cache功能的。然而,如果确实需要,就必须考虑。如果MAR中PC位被从1变到0,已经被Cache缓存的外部存储器地址保持Cache关系,并且访问那些地址仍为命中。如果外部存储器地址在L2缺失,MAR位是唯一的参考这包括L2是全SRAM的情况,因为没有L2 Cache,这也可以被解释为一个L2缺失。如果在各个外部存储器地址空间中所有地址被设置成不可Cache缓存,首先需要被write back和invalidate。3.11.2在运行中改变Cache尺寸在运行中改变Cache尺寸可能对一些应用是有必要的,例如有的任务把L2作为SRAM,将程序、一些全局变量等都放在L2 SRAM更有利; 有的程序把L2大部分作为Cache更有利。当Cache尺寸被改变时,需要按照一定的步骤执行以保证正确性。改变L2 Cache尺寸的具体步骤如表3.18所示,该步骤适用于L1P和L1D Cache。
表3.18为L1P、L1D和L2改变Cache尺寸的步骤
切换到执行更多Cache更少SRAM1 用DMA或copy方式将需要的代码数据移出将被转换为Cache的SRAM
2 等待步骤1完成
3 改变Cache大小,使用Cache_setL1pSize、Cache_setL1dSize或Cache_setL2Size更少Cache更多SRAM1 减小Cache大小,使用Cache_setL1pSize、Cache_setL1dSize或Cache_setL2Size
2 DMA或拷贝回任何需要的代码数据
3 等待步骤2完成
3.12优化Cache性能3.12.1Cache性能特征
Cache性能多半依赖于重用Cache Line。访问没有被Cache缓存的存储器中的一个行会导致内核出现阻塞周期。只要这个行被保留在Cache中,随后对该行的访问不会导致任何阻塞。因而,该行在被从Cache驱逐前越经常被使用,阻塞周期越少。因此,优化一个应用的Cache性能的一个重要目标是最大化Cache Line重用这可以通过恰当的代码和数据的存储器布局,以及改变内核存储器访问顺序来实现。为了执行这些优化,用户必须熟悉Cache存储器架构,熟悉在Cache存储器中独有的特征,如行大小、关联性、容量、替换机制、读/写分配、缺失流水和写缓冲。3.12.2阻塞情况
在C66x器件上最常见的阻塞情况如下。1 交叉路径阻塞Cross Path Stall当一个指令试图通过一个交叉路径去读一个在之前周期被更新的寄存器,一个阻塞周期被引入。编译器在任何可能的时候试图自动避免这些阻塞。2 L1D读和写命中内核访问在L1D SRAM或Cache命中通常不会导致阻塞,除非与其他请求者存在访问冲突。访问优先级被带宽管理设置控制。3 L1D Cache写命中内核写那些在L1D Cache命中的区域通常不会导致阻塞。然而,在高速率情况下,一个写命中流使之前干净的CleanCache Line变成Dirty,可以导致阻塞周期。原因是一个Tag更新缓冲,其排队缓冲cleantodirty转换到L1D Tag RAM的L2拷贝这也称为影子tag RAM,被用于snoop Cache一致性协议。4 L1D Bank冲突L1D存储器被组织成832字节块。并行访问都命中L1D的同一个bank,导致1个周期阻塞。5 L1D读缺失由于L2 SRAM、L2 Cache或外部存储器的行分配,阻塞周期被引入。L1D读缺失可以被以下情况加长。① L2 Cache读缺失: 数据必须先从外部存储器取出,阻塞周期数取决于特定的器件和外部存储器类型。② L2访问bank冲突: L2每次只可以服务一个请求,访问优先级别由带宽管理设置控制。L2请求者包括L1P Line Fills、L1D Line Fills、Write Buffer、Tag Update Buffer、Victim Buffer、IDMA或EDMA及Cache一致性操作。③ L1D Write Buffer Flush: 如果写缓冲包含数据并且一个读缺失发生,在L1D读缺失被服务之前,写缓冲首先完全排干。为保持写之后紧跟一个读操作的适当的顺序,这是需要的。通过L2访问/bank冲突和L2 Cache写缺失the Write Buffer Data Misses L2 Cache,写缓冲排干可以被拉长。④ L1D Victim缓冲写回: 如果Victim缓冲包含数据并且一个读缺失发生,在L1D读缺失被服务之前,内容首先被写回L2。对于写后紧随一个读,保持正确的顺序是必要的。写回可以被L2访问/bank冲突加长。连续的、并行的缺失会部分重叠,假如没有任何以上阻塞加长的状况并且两个并行、连续的缺失不是对同一Set。6 L1D写缓冲满如果一个L1D写缺失发生,并且写缓冲满,阻塞发生直到一个条目有效。写缓冲排干可以被以下情况加长。① L2 Cache读缺失: 数据必须首先被从外部存储器取出。阻塞周期数量取决于特定器件和外部存储器类型。② L2访问bank冲突: 每次L2只可以服务一个请求。访问的优先级由带宽管理设置管理。③ L1P读命中: 在L1P SRAM或Cache命中,内核访问通常不会导致阻塞,除非一个访问与其他请求者冲突或者到L1P ROM的访问具有等待状态。访问优先级由带宽管理设置控制。L1P请求者包含核程序访问、IDMA、EDMA和Cache一致性操作。7 L1P读缺失对于来自L2 SRAM、L2 Cache和外部存储器的行分配,阻塞周期被引入。L1P读缺失阻塞可以被以下情况加长。① L2 Cache读缺失: 首先数据必须从外部存储器取出。阻塞周期数取决于特定器件和外部存储器。② L2访问块冲突: 每次L2只可以服务一个请求。访问优先级别由带宽管理设置控制。L2请求者包含L1P Line Fills、L1D Line Fills、Write Buffer、Tag Update Buffer、Victim Buffer、IDMA或EDMA和Cache一致性操作。连续的缺失会部分交叠,假如没有任何一个以上阻塞加长情况发生。图3.13显示了C66x存储器结构,其中会有所有重要特征的详细描述。
图3.13C66x Cache存储器结构
3.12.3优化技术概览优化技术聚焦于L1 Cache的效率。因为L1特征容量、关联性、行大小比L2 Cache特征更严格,优化L1几乎肯定意味着L2 Cache也被高效地使用,而只优化L2 Cache,则没有很多好处。对于应用中的通用部分,具有很大不可预期的存储器访问,推荐使用L2 Cache。对时间严苛的信号处理算法,L1和L2 SRAM必须被使用。使用EDMA或IDMA,数据可以被直接流入L1 SRAM; 或使用EDMA,流入L2 SRAM。然后,存储器访问可以针对L1 Cache优化。有两个重要途径来减少Cache间接成本。1. 减少Cache缺失数在L1P、L1D和L2 Cache减少Cache缺失数可以通过以下途径获得:1 最大化Cache重用。访问在一条Cache Line的所有存储器位置。在一条Cache Line中相同存储器位置必须被重用,越经常越好。或者相同数据被重读或新数据被写到已经被Cached的位置,这样随后的读操作会命中。2 只要Cache Line还在重用,避免驱逐。如果数据被分配进存储器,当它被访问时,对应Cache路数没有被超出,驱逐可以被阻止如果比Cache可用路数更多的行被映射到同一Set,路数就被超出。如果这不可能,通过在时间上分开访问那些导致更多驱逐的地址,驱逐可以被延长。同样,可以让行在一个被控制的方式被驱逐,依赖LRU替换机制,那样只有行不再被使用时才被驱逐。2. 减少每个缺失阻塞数通过充分利用缺失流水实现。对于优化Cache性能,采用topdown方式是一个好的策略。在应用级开始,再到过程级,并且如有必要可以考虑算法级优化。应用级优化方法倾向于直接应用,典型地对全局性能提升具有更高的影响。如果必须,使用更低级别优化方法,可以执行微调。3.12.4应用级优化在应用级和系统级,为了实现更佳的Cache性能,以下建议是非常重要的。1. 分配数据流到外部存储器或L1L2 SRAM对于DSP内核与一个外围设备或协处理器进行数据流交互的场景,使用DMA传送数据流,建议在L1或L2 SRAM中分配数据缓冲。数据流在L1或L2存储器分配缓冲,具有以下优点。1 L1和L2 SRAM更接近内核,因而,可以减少延迟。如果缓冲被分配在外部存储器,数据会首先通过DMA从外围设备写到外部存储器,之后被L2 Cache缓存,最后在到达核之前还需要被L1D Cache缓存。2 对于通过Cache控制器到L2 SRAM的数据访问,Cache一致性自动维护。如果缓冲被分配在外部存储器,用户必须手动执行L2 Cache一致性操作,小心地维持数据一致性。在有些情况下,由于存储器容量限制,缓冲可能必须分配到外部存储器。3 由于一致性操作,不会产生额外的延迟。延时可以被认为是添加到用于处理缓冲数据需要的时间。在一个典型的双缓冲机制中,选择缓冲的尺寸时就必须考虑。对于快速原型应用,应用DMA双缓冲机制被认为消耗太长时间,应该尽量避开,分配所有代码和数据在外部存储器,使用L2作为全部Cache可能会是一个恰当的方法。一旦正确的应用功能被验证,存储器管理瓶颈和关键的算法可以被确定和被优化。2. 使用L1 SRAMC66x器件提供L1D和L1P SRAM,可能被用作代码和数据,对Cache损失敏感,如:1 性能关键的代码和数据;2 代码和数据被很多算法共享;3 代码和数据被经常访问;4 函数具有大的代码尺寸或大的数据结构;5 数据结构因不规律的访问会使Cache更低效;6 流缓冲如L2很小的器件,最好配置为Cache。由于L1 SRAM大小是有限的,因此需要很小心地决定什么代码和数据应该分配在L1 SRAM。分配大量的L1 SRAM可能需要减少L1 Cache尺寸,对于代码和数据在L2和外部存储器的情况,这意味着更低的性能。L1 SRAM尺寸可以保持更小,如果代码和数据可以根据需要被复制到L1 SRAM,使用代码、数据覆盖。IDMA可被用来快速地从L2 SRAM寻找代码或数据。如果代码、数据要从外部存储器寻找,EDMA必须被使用。然而,非常频繁的寻找可能会导致比用缓冲更高的代价。因而在SRAM和Cache尺寸之间,需要一个权衡。3. 区分信号处理和常规处理代码在一个应用中,区分信号处理类型和常规处理类型可能非常有益。常规处理通常包含控制流和条件分支,这些代码没有呈现多少并行性,而且执行依赖很多条件,处理的过程通常是不可预测的。也就是说,数据存储器访问大多数是随机的,访问程序存储器是线性的,具有很多分支,这使得优化更加困难。因而,在L2 SRAM足够保留整个应用的代码和数据的情况下,推荐分配常规代码和相关的数据到外部空间并且允许L2 Cache去处理存储器访问。这使得对性能严苛的信号处理代码,有更多的L2存储空间可用。对于不可预测的常规代码类型,L2 Cache应当被设置成尽可能大。Cache可以被配置在32~256KB。DSP代码和数据可能从被分配到L2 SRAM或L1 SRAM中获益。分配进L2 SRAM减少间接Cache损失,并给用户更多对存储器访问的控制,因为只有L1 Cache被包含,其行为更加容易去分析。在内核访问数据的方式上,允许用户修改一些算法或改变数据结构,以提供更加Cache友好的存储器访问形式。分配进L1 SRAM消除任何全部Cache,并且除了bank冲突,不需要存储器优化。3.12.5过程级优化随着数据和函数被分配进存储器的方式以及函数被调用的方式的改变,过程级优化需要被考虑。那些基于线性的存储器模型实现的算法例如FIR滤波等,不需要对单个算法进行优化。只有当通过算法访问的数据结构优化产生更高效的Cache使用时,算法才需要被优化。在多数情况下,过程级优化是有效的。除了一些算法如FFT,为了利用Cache,其算法结构必须被修改。一个Cache优化的FFT在C66x DSP库DSPLIB中提供。过程级优化的目标是减小Cache缺失的数量和一个缺失相关的阻塞周期。通过减少被Cache缓存的存储器数量和重用已经被Cache缓存的行,可以减少缺失的数量。可以通过避免驱逐和写入到预分配的行实现重用。通过利用缺失流水,一个缺失的阻塞周期可以被减少。我们可以区分以下三种不同读缺失场景:1 所有工作集的数据、代码都纳入到Cache按照定义没有容量缺失,但是冲突缺失发生。通过在存储器中连续性分配代码或数据,冲突缺失可以被减少。2 数据集比Cache大、连续分配,并且没有重用。冲突缺失发生,但是没有容量缺失因为数据没有被重用。冲突缺失可以被减少,例如通过交叉Cache Set。3 数据集比Cache更大,容量缺失因为一些数据被重用并且冲突缺失发生。通过将数据的Set分开并且每次只处理一个Set,冲突和容量缺失可以被减少。这个方法指的是分割数据组,并且一次处理一个组。采用链式chain处理,除了chain中的第一个算法为强制性缺失,在链式处理中一个算法的结果成为下一个算法的输入,这样减少Cache缺失的机会。以下介绍一些应用场景中,过程级Cache优化设计的经验。1. 通过选择相应的数据类型减少存储器带宽需求数据类型选择需要确保存储器效率。例如,如果数据长度最大是16bit,应该被声明为short类型而不是integer。这减半了数组对存储器的需求,也减少了强制缺失因子为2。典型地,接受新数据类型只需要算法中的一个小改变。因为更小的数据容器可以允许SIMD优化被编译器执行,算法可以执行得更快。2. 链式处理链式处理通常的流程是一个算法的结果作为下一个算法的输入。如果算法操作与链式处理流程不匹配也就是说,结果放置的数组和输入不同,会产生较大的Cache缺失损失。例如,输入数组被分配进L1D,但是输出通过写缓冲被传送到下一个更低存储器级L2或外部存储器。然后,当下一个算法读该数据时,又承受缺失的代价。相反,如果第一个算法的输出被写到L1D,然后数据可以从Cache中直接被重用,则无须引起Cache阻塞。对链式处理,有很多可能的配置。链式处理概念示意如图3.14所示。
图3.14链式处理示意图
3. 避免L1P冲突缺失在这个读缺失场景,所有工作集代码适合Cache定义没有容量缺失,但是冲突缺失发生。存储器地址映射到相同Set并且没有包含在同一Cache Line会互相驱逐。编译和连接不会考虑Cache冲突,在执行过程中不适当的存储器布局可能导致冲突缺失。通常,这可以通过在存储器中连续分配在一些本地时间窗内访问的代码解决。考虑示例3.5的代码: 假设function_1和function_2已经被连接器放置,并且它们在L1P中交叠,如图3.15所示。当function_1第一次被调用,它被分配进L1P导致3个缺失1。一个紧接着调用的function_2导致其代码被分配在L1P,导致5个缺失2。这也会驱逐function_1的部分代码Cache Line 3和4,因为这些行在L1P交叠3。当在下一个循环,function_1又被调用,这些行必须被调进L1P,却又将被function_2驱逐。因而,对于所有随后的循环,每个函数调用导致两个缺失,每个循环总共4个L1P缺失。这些类型缺失被称为冲突缺失。通过分配两个函数代码到不冲突的Set,这些冲突可以被完全避免。最直接的方式是在存储器连续放置两个程序代码。注意: 也可以移动function_2到任何与function_1没有Set冲突的位置,这也可以阻止驱逐。然而,第一个方法有优势,用户不必担心绝对地址位置,只需简单改变函数在存储器中的顺序。
图3.15避免L1P驱逐
【示例3.5】L1P冲突。
for i=0; i L2SRAM
.GROUP L2SRAM
{
.text:_function_1
.text:_function_2
.text
}
}
连接器会按照GROUP声明中指定的顺序连接所有段。在这个例子中,function_1代码接着的是function_2,然后接着的是分配在该段的其他函数,在源代码中不需要被改变。然而,小心使用mo编译器优化选项,可能导致总的代码量增大,因为任何包含代码的段会在32字节分界线对齐。注意,连接器只能放置完整段,而不是分配存在于相同段的每个函数。如果预编译的库或对象文件多个函数在一个段或没有用mo编译,没有办法重新分配每个函数到不同的段,除非重新编译库。`2 使用SECTION编译指示为了避免使用mo的缺点,通过使用SECTION编译指示,只有那些需要连续放置的函数可以被分配到单独段中。
#pragma
CODE_SECTION 在函数定义前:
#pragma CODE_SECTIONfunction_1,".funct1"
#pragma CODE_SECTIONfunction_2,".funct2"
void function_1{}
void function_2{}
连接命令文件可以被指定如下:
...
SECTIONS
{
.cinit L2SRAM
.GROUP L2SRAM
{
.funct1 .funct2
.text
}
...
}
在同一个循环中或者在一些时段中反复被调用的函数,可以考虑被重新安排。如果Cache容量不足以保持一个循环的所有函数,如果为了获得代码重用、不被驱逐,循环必须被分割。这可能提高对临时缓冲的存储器需求来保持输出数据。假设合并的function_1和function_2的代码尺寸比L1P尺寸更大。在示例3.6,代码循环被分割,这样两个函数可以从L1P重复地被执行,从而显著地减少缺失。然而,临时缓冲tmp[ ]必须保持从每次调用function_1的所有中间结果,导致了一定的数据依赖性。【示例3.6】代码分割从L1P执行。
for i=0; i L2SRAM
{
.mydata:w
.mydata:x
.mydata:pad
.mydata:h
}
...
}
6. 避免容量缺失在这个读缺失场景,数据被重用,但是数据集比Cache大,导致容量和冲突缺失。通过分割数据集并每次处理一个子块,这些缺失可以被消除每个子块比Cache小。这个方法被指为分块block或平铺tiling。例如用一个参考向量和4个不同输入向,点乘程序被调用4次:
short in1[N];
short in2[N];
short in3[N];
short in4[N];
short w [N];
r1 = dotprodin1, w, N;
r2 = dotprodin2, w, N;
r3 = dotprodin3, w, N;
r4 = dotprodin4, w, N;
假设每个数组是L1D容量的两倍。对于首次调用in1[ ]和w[ ],预期为强制缺失。对于剩下的调用,对于in2[ ]、in3[ ]和in4[ ],预期为强制缺失; 但是会更愿意从Cache重用w[ ]。然而,在每次调用后,因为容量不够,w[ ]起始已经被w[ ]的结束替代。对于w[ ],后续调用后又遭受缺失。如果处理完in1[ ]的14并开始处理in2[ ],可以重用刚刚分配进Cache的w[ ]元素。同样的,在计算完另一个N4输出,跳过去处理in3[ ]和最后到in4[ ]。在那之后,开始计算对于in1[ ]第二个N4输出,。这个结构代码会看起来像如下这样:
for i=0; i
|
|