/*---------------------------------------------------------------------- File: dctdma.c Description: DSP program to perform host request. Mainly processes 64 32-bit word block from host. Transfer between dsp and host via pci-dma. * As DMA is done with pc, make sure the transfer blocks are situated outside the regularly accessed data region. In this case the dma blocks are in external memory. -----------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #define BUFSIZE 1024 #define IMAGE_LEN 256 #define IMAGE_SIZE (IMAGE_LEN*IMAGE_LEN) #define BLOCK_LEN 8 #define BLOCK_SIZE (BLOCK_LEN*BLOCK_LEN) /************************************************** MailBox Routines **************************************************/ void MailBox_Setup (void) { int Dummy; (*(volatile unsigned int *)0x01700038) = 0x00000010; // Choose AIMB1, AOMB1 Dummy = (*(volatile unsigned int *)0x01700000); (*(volatile unsigned int *)0x01700038) |= 0x00030000; // Clear previous mailbox status. } int MailBox_GetCommand (void) { int HostCommand; while (!((*(volatile unsigned int *)0x01700038) & 0x00010000)); HostCommand = (*(volatile unsigned int *)0x01700000); (*(volatile unsigned int *)0x01700038) |= 0x00010000; return HostCommand; } void MailBox_SendCommand (int HostCommand) { (*(volatile unsigned int *)0x01700010) = (unsigned int) HostCommand; //===== Optional, we can wait until the host read the message. ===== // while (!((*(volatile unsigned int *)0x01700038) & 0x00020000)); // (*(volatile unsigned int *)0x01700038) |= 0x00020000; } /************************************************** DMA Routines **************************************************/ #pragma DATA_SECTION (ReceiveDmaBuffer, ".edata") #pragma DATA_SECTION (SendDmaBuffer, ".edata") int ReceiveDmaBuffer[64]; int SendDmaBuffer[64]; void DMA_Setup (void) { DMA_STOP (2); DMA_STOP (0); *(volatile unsigned int *)(cpldBaseAddr+CPLD_FIFOSTAT_OFFSET) &= 0xfc; //--- Send DMA (Channel 0) --- DMA0_PRIMARY_CTRL = (DMA_RELOAD_NONE << 30) // Don't reload destination address, fixed | (DMA_RELOAD_NONE << 28) // Don't reload source address, dsp will reload. | (0 << 27) // Emode=0, DMA not halted during emulation halt. | (0 << 26) // FS=0, No frame sync. | (1 << 25) // TCINT=1, enable dma interrupt. | (DMA_DMA_PRI << 24) // DMA has priority of CPU on internal bus. | (SEN_EXT_INT6 << 19) // Write Sync from external interrupt pin 6 (evm6x requirement). | (SEN_NONE << 14) // No Read Sync. | (DMA_GNDX_A << 13) // Use global index register A as programmable index. | (0 << 12) // no count reload. | (DMA_SPLIT_DIS << 10) // Disable split channel mode. | (DMA_ESIZE32 << 8) // Set element size to 32-bit. | (DMA_ADDR_NO_MOD << 6) // Fix destination address. | (DMA_ADDR_INC << 4) // Auto-increment source address after each transfer. | (DMA_STOP_VAL ); // Stop dma now. Start later, after configuration. DMA0_SECONDARY_CTRL = (1 << 15) // Clear any prior WSYNC status. | (1 << 13) // Clear any prior RSYNC status. | (1 << 7); // Enable block-transfer-end interrupt. DMA0_DEST_ADDR = PCI_MAP1_FIFO_ADDR; // Global address set after evm_init() is called. intr_map (CPU_INT10, ISN_DMA_INT0); INTR_CLR_FLAG (CPU_INT10); //--- Receive DMA (Channel 2) --- DMA2_PRIMARY_CTRL = (DMA_RELOAD_NONE << 30) // Don't reload destination address, fixed. | (DMA_RELOAD_NONE << 28) // Don't reload source address, dsp will reload. | (0 << 27) // Emode=0, DMA not halted during emulation halt. | (0 << 26) // FS=0, No frame sync. | (1 << 25) // TCINT=1, enable dma interrupt. | (DMA_DMA_PRI << 24) // DMA has priority of CPU on internal bus. | (SEN_NONE << 19) // No Wrtie Sync. | (SEN_EXT_INT5 << 14) // Read Sync from external interrupt pin 5 (EVM6X requirement). | (DMA_GNDX_A << 13) // Use global index register A as programmable index. | (0 << 12) // no count reload. | (DMA_SPLIT_DIS << 10) // Disable split channel mode. | (DMA_ESIZE32 << 8) // Set element size to 32-bit. | (DMA_ADDR_INC << 6) // Auto-increment destination address after each transfer. | (DMA_ADDR_NO_MOD << 4) // Fix source address. | (DMA_STOP_VAL ); // Stop dma now. Start later, after configuration. DMA2_SECONDARY_CTRL = (1 << 15) // Clear any prior WSYNC status. | (1 << 13) // Clear any prior RSYNC status. | (1 << 7); // Enable block-transfer-end interrupt. DMA2_SRC_ADDR = PCI_MAP1_FIFO_ADDR; // Global address set after evm_init() is called. intr_map (CPU_INT11, ISN_DMA_INT2); INTR_CLR_FLAG (CPU_INT11); return; } void DMA_Receive (int *block) { // int i; DMA2_DEST_ADDR = (unsigned int) ReceiveDmaBuffer; DMA2_XFER_COUNTER = 64; DMA_START (2); *(volatile unsigned int *)(cpldBaseAddr+CPLD_FIFOSTAT_OFFSET) |= 0x02; while (!INTR_CHECK_FLAG(CPU_INT11)); DMA2_SECONDARY_CTRL &= 0xffffffbf; INTR_CLR_FLAG (CPU_INT11); *(volatile unsigned int *)(cpldBaseAddr+CPLD_FIFOSTAT_OFFSET) &= 0xfd; memcpy (block, ReceiveDmaBuffer, 64 * sizeof (int)); DMA_STOP (2); } void DMA_Send (int *block) { // int i; memcpy (SendDmaBuffer, block, 64 * sizeof (int)); DMA0_SRC_ADDR = (unsigned int) SendDmaBuffer; DMA0_XFER_COUNTER = 64; DMA_START (0); *(volatile unsigned int *)(cpldBaseAddr+CPLD_FIFOSTAT_OFFSET) |= 0x01; while (!INTR_CHECK_FLAG(CPU_INT10)); INTR_CLR_FLAG (CPU_INT10); DMA0_SECONDARY_CTRL &= 0xffffffbf; *(volatile unsigned int *)(cpldBaseAddr+CPLD_FIFOSTAT_OFFSET) &= 0xfe; DMA_STOP (0); } /************************************************** DCT and IDCT functions **************************************************/ /* Coefficients in Q1.12 format */ const int coe[8][8]= { 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 2008, 1702, 1137, 399, -399, -1137, -1702, -2008, 1892, 783, -783, -1892, -1892, -783, 783, 1892, 1702, -399, -2008, -1137, 1137, 2008, 399, -1702, 1448, -1448, -1448, 1448, 1448, -1448, -1448, 1448, 1137, -2008, 399, 1702, -1702, -399, 2008, -1137, 783, -1892, 1892, -783, -783, 1892, -1892, 783, 399, -1137, 1702, -2008, 2008, -1702, 1137, -399, }; /* Quantizer in integer format. */ const int quant[64] = { 16, 11, 10, 16, 24, 40, 51, 61, 12, 12, 14, 19, 26, 58, 60, 55, 14, 13, 16, 24, 40, 57, 69, 56, 14, 17, 22, 29, 51, 87, 80, 62, 18, 22, 37, 56, 68, 109, 103, 77, 24, 35, 55, 64, 81, 104, 113, 92, 49, 64, 78, 87, 103, 121, 120, 101, 72, 92, 95, 98, 112, 100, 103, 99 }; /* Reciprocal of quantizer in Q1.15 format. */ const int rquant15 [64] = { 0x0800, 0x0ba2, 0x0ccc, 0x0800, 0x0555, 0x0333, 0x0282, 0x0219, 0x0aaa, 0x0aaa, 0x0924, 0x06bc, 0x04ec, 0x0234, 0x0222, 0x0253, 0x0924, 0x09d8, 0x0800, 0x0555, 0x0333, 0x023e, 0x01da, 0x0249, 0x0924, 0x0787, 0x05d1, 0x0469, 0x0282, 0x0178, 0x0199, 0x0210, 0x071c, 0x05d1, 0x0375, 0x0249, 0x01e1, 0x012c, 0x013e, 0x01a9, 0x0555, 0x03a8, 0x0253, 0x0200, 0x0194, 0x013b, 0x0121, 0x0164, 0x029c, 0x0200, 0x01a4, 0x0178, 0x013e, 0x010e, 0x0111, 0x0144, 0x01c7, 0x0164, 0x0158, 0x014e, 0x0124, 0x0147, 0x013e, 0x014a }; #pragma CODE_SECTION (dct,".iprog") far void dct(int *block) { int i,j,x,y; int value[8]; /* perform 1D DCT on the rows */ for(i=0;i<64;i+=8) { for(y=0;y<8;++y) { value[y] = 0; for(x=0;x<8;++x) value[y] += (coe[y][x]*block[i+x]); } for(y=0;y<8;++y) { block[i+y] = (value[y]>>12); } } /* perform 1D DCT on the columns */ for(j=0;j<8;j++) { for(y=0;y<8;++y) { value[y]=0; for(x=0;x<8;++x) value[y] += (coe[y][x]*block[j+(x*8)]); } for(y=0;y<8;++y) block[j+(y*8)] = (value[y]>>12); } } #pragma CODE_SECTION (idct,".iprog") far void idct(int *block) { int i,j,x,y; int value[8]; /* perform 1D IDCT on the rows */ for(i=0;i<64;i+=8) { for(y=0;y<8;++y) { value[y] = 0; for(x=0;x<8;++x) value[y] += (int)(coe[x][y]*block[i+x]); } for(y=0;y<8;++y) block[i+y] = (short)(value[y]>>12); } /* perform 1D IDCT on the columns */ for(j=0;j<8;j++) { for(y=0;y<8;++y) { value[y] = 0; for(x=0;x<8;++x) value[y] += (int)(coe[x][y]*block[j+(x*8)]); } for(y=0;y<8;++y) block[j+(y*8)] = (short)(value[y]>>12); } for(i=0;i<64;i++) { if (block[i] < 0) block[i] = 0; if (block[i] > 255) block[i] = 255; } } #pragma CODE_SECTION (ExecuteCommand,".iprog") far void ExecuteCommand (unsigned int msg, int *block) { int i; switch (msg) /* Perform appropriate operation as required by host. */ { case 0: for (i=0; i<64; i++) block[i]=block[i]^0xff; break; case 1: // Perform DCT. dct (block); break; case 2: // Perform IDCT idct (block); break; case 3: // Perform DCT with JPEG quantization. dct (block); for (i=0; i<64; i++) { /* Resulting values have 15 decimal places. */ /* Hence shift 15 spaces left to obtain integral value. */ /* For negative values, 0.5 is added to the integral */ /* so that values within -1 and 0 can be round down to 0 */ /* instead of -1. */ block[i] = ((short)block[i]*(short)rquant15[i])>>14; if (block[i]<0) block[i] +=1; block[i] = block[i] >> 1; } break; case 4: // Perform IDCT with JPEG dequantization. for (i=0; i<64; i++) block[i]=block[i]*quant[i]; idct (block); break; default: /* does nothing to the block */ break; } } /************************************************** Main Loop **************************************************/ void main(int argc, char *argv[]) { int msg; int block [64]; evm_init(); DMA_Setup (); MailBox_Setup (); while (1) { //--- Wait for Host message and read the message --- msg = MailBox_GetCommand (); //--- Start DMA to read 64-word block into input buffer --- DMA_Receive (block); //--- Process the 64-word block according to the host command. ExecuteCommand (msg, block); //--- Inform host of 64-word block ready --- MailBox_SendCommand (64); //--- Start DMA to write the processed 64-word block to host --- DMA_Send (block); } return; }