复数乘法指令
TI的编译器提供的一些内联函数中可以直接调用复数乘法的汇编指令(CMPYSP,只有C66x DSP支持),完成复数乘法运算。

讯享网
src1和src2是连续的两个32位寄存器组成的register pair,dst是由四个连续的32位寄存器组成的register quadruplets。这里只是做了乘法运算。

然后用DADDSP指令可以对上面的结果中的实数部分和虚数部分分别求和,即可实现复数乘法。
( a + b i ) ( c + d i ) = a c − b d + ( a d + b c ) i \left( {a + b{\rm{i} } } \right)\left( {c + d{\rm{i} } } \right) = ac - bd + \left( {ad + bc} \right){\rm{i} } (a+bi)(c+di)=ac−bd+(ad+bc)i
另外编译器也提供了一种快速实现复共轭乘法的方式,即 p × q ∗ p\times q^* p×q∗。乘数中需要求复共轭的数 q q q放在src1寄存器对中作为 a + b i a+b\rm{i} a+bi,另一个乘数 p p p放在src2寄存器对中,依次完成CMPYSP和DSUBSP即可得到 p × q ∗ p\times q^* p×q∗的结果。

( a − b i ) ( c + d i ) = a c + b d + ( a d − b c ) i \left( {a - b{\rm{i} } } \right)\left( {c + d{\rm{i} } } \right) = ac + bd + \left( {ad - bc} \right){\rm{i} } (a−bi)(c+di)=ac+bd+(ad−bc)i
Cache映射方式
Cache的映射方式包括直接映射,全相联映射和组相联映射,后者是前两者相结合的产物。C6678的L1P Cache采用的是直接映射,存储器中的code在L1P Cache中只有唯一确定的位置。
C6678的L1D Cache采用的是两路组相联映射(two-way set associative cache),一个set里面有两个line frame,存储器中的数据映射到固定的set,但可以是任意的line frame。

C6678的cache line frame是64字节,所以地址中的Offset字段固定为6bits。一个set是128字节,如果L1D的Cache大小为4kB,那么L1D Cache可以分为32个set,所以Set字段为5bits,剩下的就是Tag字段21bits。


当L1D Cache设置为32kB时,set的数量也就变为了原来的8倍,因此Set字段需要8bits,相应的Tag字段减少为18bits。
TI Data Type
调试过程中经常需要预先往存储器中加载数据,可以通过Memory Browser窗口里的Load Memory实现。

需要加载的数据预先存在在一个“xxx.dat”文件里,按照TI Data的格式进行存放,在加载的时候CCS就会根据文件头的信息把数据加载到指定的位置。

帧头的数都是十六进制表示的!可以在CCS的Help->Help Comtents里搜索“data format”找到相关的介绍。

数据格式“9”表示一种比较新的数据格式说明方式,具体数据格式由最后一个数决定。数据个数就是数据的行数,因为一行一个数据。具体数据格式如下表:
| 具体数据格式(十六进制) | 含义 |
|---|---|
| 0 | 64bit Hex TI-style |
| 1 | 64bit Hex C-style (带0x前缀) |
| 2 | 64bit Floating Point |
| 3 | Exponential Float (指数表示的浮点数) |
| 4 | 32bit Hex TI-style |
| 5 | 32bit Hex C-style |
| 6 | 32bit Signed Int |
| 7 | 32bit Unsigned Int |
| 8 | 32bit Binary |
| 9 | 32bit Floating Point |
| A | 32bit Exponential Float |
| B | 16bit Hex TI-style |
| C | 16bit Hex C-style |
| D | 16bit Signed Int |
| E | 16bit Unsigned Int |
| F | 16bit Binary |
| 10 | 8bit Hex TI-style |
| 11 | 8bit Hex C-style |
| 12 | 8bit Signed Int |
| 13 | 8bit Unsigned Int |
| 14 | 8bit Binary |
| 15 | Character |
| 16 | Packed Char |
QDMA的使用
有时候需要手动启动DMA并且随时需要对PaRAM进行修改,而不是等待外部事件触发,那么就可以用QDMA来实现。QDMA能够在写完PaRAM时就启动DMA传输。实际应用过程中可以有这几点需要考虑:
- 硬件初始化
- 中断服务函数
- 启动传输
下面是C6678上用于实现矩阵转置的一个类。三个成员函数分别对应我提到的三点要考虑的地方。
#ifndef CTSPSMANAGER_H #define CTSPSMANAGER_H #include <csl_edma3.h> #define TPSP_PARAM_NUM (10) #define TSPS_QDMA_CHANNEL (0) #define TSPS_TCC_CODE (8) #define TSPS_SYSEVT_EDMA3R0 (38) #define TSPS_REGION CSL_EDMA3_REGION_0 class CTspsManager {
private: CSL_Edma3Handle m_hEdma; CSL_Edma3Obj m_Obj; Bool m_bInitDone; int m_nCicId; public: CTspsManager(); ~CTspsManager(); int HwInit(int coreId); void startTranspose( void *restrict pSrc, void *restrict pDst, int nSrcWidth, int nSrcHeight, size_t nUnit); void ClearInterruptFlag(); }; #endif
讯享网
硬件初始化过程中,因为要配置中断,所以不同的核需要设置对应的片上中断控制器(CIC)。QDMA通道绑定队列与PaRAM,使能通道。同时也需要使能PaRAM中TCC code对应的DMA通道,和这个DMA通道的中断使能。清中断的时候需要清系统中断和EMDA的中断挂号寄存器。
讯享网int CTspsManager::HwInit(int coreId) {
CSL_Status status; CSL_Edma3HwSetup hwSetup; UInt nChannel; CSL_Edma3HwDmaChannelSetup hwDmaSetup[] = CSL_EDMA3_DMACHANNELSETUP_DEFAULT; CSL_Edma3HwQdmaChannelSetup hwQdmaSetup[] = CSL_EDMA3_QDMACHANNELSETUP_DEFAULT; if(coreId < 0 || coreId > 7) return -1; if(m_bInitDone) return 0; m_hEdma = CSL_edma3Open(&m_Obj, CSL_EDMA3CC_0, NULL, &status); assert(m_hEdma != NULL); //--------------------- Hardware Setup -------------------------- // DMA setup hwDmaSetup[TSPS_TCC_CODE].paramNum = TPSP_PARAM_NUM; hwDmaSetup[TSPS_TCC_CODE].que = CSL_EDMA3_QUE_0; hwSetup.dmaChaSetup = hwDmaSetup; // end of DMA setup // QDMA setup hwQdmaSetup[TSPS_QDMA_CHANNEL].paramNum = TPSP_PARAM_NUM; hwQdmaSetup[TSPS_QDMA_CHANNEL].que = CSL_EDMA3_QUE_0; hwQdmaSetup[TSPS_QDMA_CHANNEL].triggerWord = CSL_EDMA3_TRIGWORD_DEFAULT; hwSetup.qdmaChaSetup = hwQdmaSetup; // end of QDMA setup CSL_edma3HwSetup(m_hEdma, &hwSetup); //--------------------- end of Hardware Setup -------------------------- //--------------------- Queue Priority Setup -------------------------- CSL_edma3SetEventQueuePriority(m_hEdma, CSL_EDMA3_QUE_0, CSL_EDMA3_QUE_PRI_0); CSL_edma3SetEventQueuePriority(m_hEdma, CSL_EDMA3_QUE_1, CSL_EDMA3_QUE_PRI_1); CSL_edma3SetEventQueuePriority(m_hEdma, CSL_EDMA3_QUE_2, CSL_EDMA3_QUE_PRI_2); CSL_edma3SetEventQueuePriority(m_hEdma, CSL_EDMA3_QUE_3, CSL_EDMA3_QUE_PRI_3); //--------------------- end of Queue Priority Setup -------------------------- CSL_edma3QdmaRegionAccessDisable(m_hEdma, TSPS_REGION, 0xF); CSL_edma3QdmaRegionAccessEnable(m_hEdma, TSPS_REGION, 1 << TSPS_QDMA_CHANNEL); CSL_edma3DmaRegionAccessDisable(m_hEdma, TSPS_REGION, 0xFFFFFFFF, 0xFFFFFFFF); CSL_edma3DmaRegionAccessEnable(m_hEdma, TSPS_REGION, 1 << TSPS_TCC_CODE, 0); CSL_edma3InterruptLoEnable(m_hEdma, TSPS_REGION, 1 << TSPS_TCC_CODE); //--------------------- end of Region Access Setup -------------------------- CSL_edma3QDMAChannelEnable(m_hEdma, TSPS_REGION, TSPS_QDMA_CHANNEL); CSL_edma3ClearDMAChannelEvent(m_hEdma, TSPS_REGION, TSPS_TCC_CODE); CSL_edma3DMAChannelEnable(m_hEdma, TSPS_REGION, TSPS_TCC_CODE); // CIC0 is used to connect EMDA finish interrupt to CPU m_nCicId = (coreId < 4) ? 0 : 1; nChannel = coreId % 4 * 11 + 33; // attach to host interrupt ID 22 CpIntc_clearSysInt(m_nCicId, TSPS_SYSEVT_EDMA3R0); CpIntc_enableSysInt(m_nCicId, TSPS_SYSEVT_EDMA3R0); CpIntc_mapSysIntToHostInt(m_nCicId, TSPS_SYSEVT_EDMA3R0, nChannel); CpIntc_enableHostInt(m_nCicId, nChannel); CpIntc_enableAllHostInts(m_nCicId); return 0; } void CTspsManager::startTranspose( void *restrict pSrc, void *restrict pDst, int nSrcWidth, int nSrcHeight, size_t nUnit) {
CSL_Status status; CSL_Edma3ParamSetup paramSetup; CSL_Edma3ParamHandle hParam; Cache_wb(pSrc, nSrcWidth * nSrcHeight * nUnit, Cache_Type_ALLD, TRUE); hParam = CSL_edma3GetParamHandle(m_hEdma, TPSP_PARAM_NUM, &status); paramSetup.option = CSL_EDMA3_OPT_MAKE(CSL_EDMA3_ITCCH_EN, \ CSL_EDMA3_TCCH_DIS, \ CSL_EDMA3_ITCINT_DIS, \ CSL_EDMA3_TCINT_EN, \ TSPS_TCC_CODE, \ CSL_EDMA3_TCC_NORMAL,\ CSL_EDMA3_FIFOWIDTH_NONE, \ CSL_EDMA3_STATIC_DIS, \ CSL_EDMA3_SYNC_AB, \ CSL_EDMA3_ADDRMODE_INCR, \ CSL_EDMA3_ADDRMODE_INCR); paramSetup.srcAddr = (uint32_t)pSrc; paramSetup.aCntbCnt = CSL_EDMA3_CNT_MAKE(nUnit, nSrcHeight); // (acnt, bcnt) paramSetup.dstAddr = (uint32_t)pDst; paramSetup.srcDstBidx = CSL_EDMA3_BIDX_MAKE(nSrcWidth * nUnit, nUnit); // (src, dst) paramSetup.linkBcntrld = CSL_EDMA3_LINKBCNTRLD_MAK (CSL_EDMA3_LINK_NULL, 0); paramSetup.srcDstCidx = CSL_EDMA3_CIDX_MAKE(nUnit, nSrcHeight * nUnit); // (src, dst) paramSetup.cCnt = nSrcWidth; CSL_edma3ParamSetup(hParam, ¶mSetup); } void CTspsManager::ClearInterruptFlag() {
CSL_edma3ClearLoPendingInterrupts(m_hEdma, TSPS_REGION, 1 << TSPS_TCC_CODE); CpIntc_clearSysInt(m_nCicId, TSPS_SYSEVT_EDMA3R0); }
参考资料
- SPRU187U-TMS320C6000 Optimizing Compiler v7.4
- SPRUGH7-TMS320C66x DSP CPU and Instruction Set Reference Guide
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/22627.html