📄 xdmaps.c
字号:
* @param Lc is the Loop counter register, can either be 0 or 1.* @param LoopIterations: the number of interations, LoopInterations - 1* will be encoded in the DMALP instruction.** @return The number of bytes for this instruction which is 2.** @note None.******************************************************************************/inline int XDmaPs_Instr_DMALP(char *DmaProg, unsigned Lc, unsigned LoopIterations){ /* * DMALP encoding * 15 ... 8 7 6 5 4 3 2 1 0 * | iter[7:0] |0 0 1 0 0 0 lc 0 */ *DmaProg = (u8)(0x20 | ((Lc & 1) << 1)); *(DmaProg + 1) = (u8)(LoopIterations - 1); return 2;}/****************************************************************************//**** Construction function for DMALPEND instruction. This function fills the* program buffer with the constructed instruction.** @param DmaProg is the DMA program buffer, it's the starting address* for the instruction being constructed* @param BodyStart is the starting address of the loop body. It is used* to calculate the bytes of backward jump.* @param Lc is the Loop counter register, can either be 0 or 1.** @return The number of bytes for this instruction which is 2.** @note None.******************************************************************************/inline int XDmaPs_Instr_DMALPEND(char *DmaProg, char *BodyStart, unsigned Lc){ /* * DMALPEND encoding * 15 ... 8 7 6 5 4 3 2 1 0 * | backward_jump[7:0] |0 0 1 nf 1 lc bs x * * lc: loop counter * nf is for loop forever. The driver does not support loop forever, * so nf is 1. * The driver does not support conditional LPEND, so bs is 0, x is 0. */ *DmaProg = 0x38 | ((Lc & 1) << 2); *(DmaProg + 1) = (u8)(DmaProg - BodyStart); return 2;}/* * Register number for the DMAMOV instruction */#define XDMAPS_MOV_SAR 0x0#define XDMAPS_MOV_CCR 0x1#define XDMAPS_MOV_DAR 0x2/****************************************************************************//**** Construction function for DMAMOV instruction. This function fills the* program buffer with the constructed instruction.** @param DmaProg is the DMA program buffer, it's the starting address* for the instruction being constructed* @param Rd is the register id, 0 for SAR, 1 for CCR, and 2 for DAR* @param Imm is the 32-bit immediate number** @return The number of bytes for this instruction which is 6.** @note None.******************************************************************************/inline int XDmaPs_Instr_DMAMOV(char *DmaProg, unsigned Rd, u32 Imm){ /* * DMAMOV encoding * 15 4 3 2 1 10 ... 8 7 6 5 4 3 2 1 0 * 0 0 0 0 0 |rd[2:0]|1 0 1 1 1 1 0 0 * * 47 ... 16 * imm[32:0] * * rd: b000 for SAR, b001 CCR, b010 DAR */ *DmaProg = 0xBC; *(DmaProg + 1) = Rd & 0x7; // *((u32 *)(DmaProg + 2)) = Imm; XDmaPs_Memcpy4(DmaProg + 2, (char *)&Imm); return 6;}/****************************************************************************//**** Construction function for DMANOP instruction. This function fills the* program buffer with the constructed instruction.** @param DmaProg is the DMA program buffer, it's the starting address* for the instruction being constructed* @return The number of bytes for this instruction which is 1.** @note None.******************************************************************************/inline int XDmaPs_Instr_DMANOP(char *DmaProg){ /* * DMANOP encoding * 7 6 5 4 3 2 1 0 * 0 0 0 1 1 0 0 0 */ *DmaProg = 0x18; return 1;}/****************************************************************************//**** Construction function for DMARMB instruction. This function fills the* program buffer with the constructed instruction.** @param DmaProg is the DMA program buffer, it's the starting address* for the instruction being constructed** @return The number of bytes for this instruction which is 1.** @note None.******************************************************************************/inline int XDmaPs_Instr_DMARMB(char *DmaProg){ /* * DMARMB encoding * 7 6 5 4 3 2 1 0 * 0 0 0 1 0 0 1 0 */ *DmaProg = 0x12; return 1;}/****************************************************************************//**** Construction function for DMASEV instruction. This function fills the* program buffer with the constructed instruction.** @param DmaProg is the DMA program buffer, it's the starting address* for the instruction being constructed* @param EventNumber is the Event number to signal.** @return The number of bytes for this instruction which is 2.** @note None.******************************************************************************/inline int XDmaPs_Instr_DMASEV(char *DmaProg, unsigned int EventNumber){ /* * DMASEV encoding * 15 4 3 2 1 10 9 8 7 6 5 4 3 2 1 0 * |event[4:0]| 0 0 0 0 0 1 1 0 1 0 0 */ *DmaProg = 0x34; *(DmaProg + 1) = (u8)(EventNumber << 3); return 2;}/****************************************************************************//**** Construction function for DMAST instruction. This function fills the* program buffer with the constructed instruction.** @param DmaProg is the DMA program buffer, it's the starting address* for the instruction being constructed** @return The number of bytes for this instruction which is 1.** @note None.******************************************************************************/inline int XDmaPs_Instr_DMAST(char *DmaProg){ /* * DMAST encoding * 7 6 5 4 3 2 1 0 * 0 0 0 0 1 0 bs x * * Note: this driver doesn't support conditional load or store, * so the bs bit is 0 and x bit is 0. */ *DmaProg = 0x08; return 1;}/****************************************************************************//**** Construction function for DMAWMB instruction. This function fills the* program buffer with the constructed instruction.** @param DmaProg is the DMA program buffer, it's the starting address* for the instruction being constructed** @return The number of bytes for this instruction which is 1.** @note None.******************************************************************************/inline int XDmaPs_Instr_DMAWMB(char *DmaProg){ /* * DMAWMB encoding * 7 6 5 4 3 2 1 0 * 0 0 0 1 0 0 1 0 */ *DmaProg = 0x13; return 1;}/****************************************************************************//**** Conversion function from the endian swap size to the bit encoding of the CCR** @param EndianSwapSize is the endian swap size, in terms of bits, it* could be 8, 16, 32, 64, or 128(We are using DMA assembly syntax)** @return The endian swap size bit encoding for the CCR.** @note None.******************************************************************************/inline unsigned XDmaPs_ToEndianSwapSizeBits(unsigned int EndianSwapSize){ switch (EndianSwapSize) { case 0: case 8: return 0; case 16: return 1; case 32: return 2; case 64: return 3; case 128: return 4; default: return 0; }}/****************************************************************************//**** Conversion function from the burst size to the bit encoding of the CCR** @param BurstSize is the burst size. It's the data width.* In terms of bytes, it could be 1, 2, 4, 8, 16, 32, 64, or 128.* It must be no larger than the bus width.* (We are using DMA assembly syntax.)** @note None.******************************************************************************/inline unsigned XDmaPs_ToBurstSizeBits(unsigned BurstSize){ switch (BurstSize) { case 1: return 0; case 2: return 1; case 4: return 2; case 8: return 3; case 16: return 4; case 32: return 5; case 64: return 6; case 128: return 7; default: return 0; }}/****************************************************************************//**** Conversion function from PL330 bus transfer descriptors to CCR value. All the* values passed to the functions are in terms of assembly languages, not in* terms of the register bit encoding.** @param ChanCtrl is the Instance of XDmaPs_ChanCtrl.** @return The 32-bit CCR value.** @note None.******************************************************************************/u32 XDmaPs_ToCCRValue(XDmaPs_ChanCtrl *ChanCtrl){ /* * Channel Control Register encoding * [31:28] - endian_swap_size * [27:25] - dst_cache_ctrl * [24:22] - dst_prot_ctrl * [21:18] - dst_burst_len * [17:15] - dst_burst_size * [14] - dst_inc * [13:11] - src_cache_ctrl * [10:8] - src_prot_ctrl * [7:4] - src_burst_len * [3:1] - src_burst_size * [0] - src_inc */ unsigned es = XDmaPs_ToEndianSwapSizeBits(ChanCtrl->EndianSwapSize); unsigned dst_burst_size = XDmaPs_ToBurstSizeBits(ChanCtrl->DstBurstSize); unsigned dst_burst_len = (ChanCtrl->DstBurstLen - 1) & 0x0F; unsigned dst_cache_ctrl = (ChanCtrl->DstCacheCtrl & 0x03) | ((ChanCtrl->DstCacheCtrl & 0x08) >> 1); unsigned dst_prot_ctrl = ChanCtrl->DstProtCtrl & 0x07; unsigned dst_inc_bit = ChanCtrl->DstInc & 1; unsigned src_burst_size = XDmaPs_ToBurstSizeBits(ChanCtrl->SrcBurstSize); unsigned src_burst_len = (ChanCtrl->SrcBurstLen - 1) & 0x0F; unsigned src_cache_ctrl = (ChanCtrl->SrcCacheCtrl & 0x03) | ((ChanCtrl->SrcCacheCtrl & 0x08) >> 1); unsigned src_prot_ctrl = ChanCtrl->SrcProtCtrl & 0x07; unsigned src_inc_bit = ChanCtrl->SrcInc & 1; u32 ccr_value = (es << 28) | (dst_cache_ctrl << 25) | (dst_prot_ctrl << 22) | (dst_burst_len << 18) | (dst_burst_size << 15) | (dst_inc_bit << 14) | (src_cache_ctrl << 11) | (src_prot_ctrl << 8) | (src_burst_len << 4) | (src_burst_size << 1) | (src_inc_bit); PDBG("CCR: es %x\r\n", es); PDBG("CCR: dca %x, dpr %x, dbl %x, dbs %x, di %x\r\n", dst_cache_ctrl, dst_prot_ctrl, dst_burst_len, dst_burst_size, dst_inc_bit); PDBG("CCR: sca %x, spr %x, sbl %x, sbs %x, si %x\r\n", src_cache_ctrl, src_prot_ctrl, src_burst_len, src_burst_size, src_inc_bit); return ccr_value;}/****************************************************************************//*** Construct a loop with only DMALD and DMAST as the body using loop counter 0.* The function also makes sure the loop body and the lpend is in the same* cache line.** @param DmaProgStart is the very start address of the DMA program.* This is used to calculate whether the loop is in a cache line.* @param CacheLength is the icache line length, in terms of bytes.* If it's zero, the performance enhancement feature will be* turned off.* @param DmaProgLoopStart The starting address of the loop (DMALP).* @param LoopCount The inner loop count. Loop count - 1 will be used to* initialize the loop counter.** @return The number of bytes the loop has.** @note None.******************************************************************************/int XDmaPs_ConstructSingleLoop(char *DmaProgStart, int CacheLength, char *DmaProgLoopStart, int LoopCount){ int CacheStartOffset; int CacheEndOffset; int NumNops; char *DmaProgBuf = DmaProgLoopStart; PDBG("Contructing single loop: loop count %d\r\n", LoopCount); DmaProgBuf += XDmaPs_Instr_DMALP(DmaProgBuf, 0, LoopCount); if (CacheLength > 0) { /* * the CacheLength > 0 switch is ued to turn on/off nop * insertion */ CacheStartOffset = DmaProgBuf - DmaProgStart; CacheEndOffset = CacheStartOffset + 3; /* * check whether the body and lpend fit in one cache line */ if (CacheStartOffset / CacheLength != CacheEndOffset / CacheLength) { /* insert the nops */ NumNops = CacheLength - CacheStartOffset % CacheLength; while (NumNops--) { DmaProgBuf += XDmaPs_Instr_DMANOP(DmaProgBuf); } } } DmaProgBuf += XDmaPs_Instr_DMALD(DmaProgBuf); DmaProgBuf += XDmaPs_Instr_DMAST(DmaProgBuf); DmaProgBuf += XDmaPs_Instr_DMALPEND(DmaProgBuf, DmaProgBuf - 2, 0); return DmaProgBuf - DmaProgLoopStart;}/*** Construct a nested loop with only DMALD and DMAST in the inner loop body.* It uses loop counter 1 for the outer loop and loop counter 0 for the* inner loop. * @param DmaProgStart The very start address of the DMA program. This is used * to caculate whether the loop is in a cache line. * @param CacheLength The icache line length, in terms of bytes. If it's zero, * the performance enhancement feture will be turned off. * @param DmaProgLoopStart The starting address of the loop (DMALP). * @param LoopCountOuter The outer loop count. Loop count - 1 will be used to * initialize the loop counter. * @param LoopCountInner The inner loop count. Loop count - 1 will be used to * initialize the loop counter. * @return the number byes the nested loop program has. *//****************************************************************************//*** Construct a nested loop with only DMALD and DMAST in the inner loop body.* It uses loop counter 1 for the outer loop and loop counter 0 for the* inner loop.** @param DmaProgStart is the very start address of the DMA program.* This is used to calculate whether the loop is in a cache line.* @param CacheLength is the icache line length, in terms of bytes.* If it's zero, the performance enhancement feature will be* turned off.* @param DmaProgLoopStart The starting address of the loop (DMALP).* @param LoopCountOuter The outer loop count. Loop count - 1 will be* used to initialize the loop counter.* @param LoopCountInner The inner loop count. Loop count - 1 will be* used to initialize the loop counter.** @return The number byes the nested loop program has.** @note None.******************************************************************************/int XDmaPs_ConstructNestedLoop(char *DmaProgStart, int CacheLength, char *DmaProgLoopStart, unsigned int LoopCountOuter, unsigned int LoopCountInner){ int CacheStartOffset; int CacheEndOffset; int NumNops; char *InnerLoopStart; char *DmaProgBuf = DmaProgLoopStart; PDBG("Contructing nested loop outer %d, inner %d\r\n", LoopCountOuter, LoopCountInner); DmaProgBuf += XDmaPs_Instr_DMALP(DmaProgBuf, 1, LoopCountOuter); InnerLoopStart = DmaProgBuf; if (CacheLength > 0) { /* * the CacheLength > 0 switch is ued to turn on/off nop * insertion */ if (CacheLength < 8) { /* * if the cache line is too small to fit both loops * just align the inner loop */ DmaProgBuf += XDmaPs_ConstructSingleLoop(DmaProgStart, CacheLength, DmaProgBuf, LoopCountInner); /* outer loop end */ DmaProgBuf += XDmaPs_Instr_DMALPEND(DmaProgBuf, InnerLoopStart, 1); /* * the nested loop is constructed for * smaller cache line */ return DmaProgBuf - DmaProgLoopStart; } /* * Now let's handle the case where a cache line can * fit the nested loops.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -