Jump to content

    

__inline__

Участник
  • Content Count

    867
  • Joined

Everything posted by __inline__


  1. Добрый день. Использую C674x в связке с внешней SDRAM: организация памяти 32M x 16 (64 МБ), 4 банка памяти, одна страница памяти 1024 байт (10 бит). Кеш L1D, L1P и L2 включены, регионы кеширования MAR для адресов 0xC0000000 ... 0xC3FFFFFF (все 64 МБ) включены в регистрах. Программа выполняется из этой SDRAM, много данных (на несколько МБ), кода - несколько сотен килобайт (от 500 кБ). Активно используется выделения памяти из кучи (через memalign(128,x) ) - указатели выровнены на длину строки кеша L2 (максимальная длина) - 128 байт. Вопрос собственно вот в чём: есть ли смысл привязываться к банкам SDRAM для ускорения доступа к данным? Например - стек - в одном банке, куча - в другом, Zero-Init, UnInit - в третьем, код (.text) - в четвёртом? Или это ничего не даст? Прилагаю файл для линковщика - с расписанными секциями и регионами памяти, который сейчас используется. Программа стартует с самого начала SDRAM 0xC0000000: #define SDRAM_BASE 0xC0000000 #define SDRAM_SIZE 0x04000000 // 64 MB #define RO_SIZE 0x00098000 // <512 kB -c -stack 0x01700000 -heap 0x02800000 MEMORY { RO o = SDRAM_BASE l = RO_SIZE RW o = SDRAM_BASE+RO_SIZE l = SDRAM_SIZE-RO_SIZE } SECTIONS { .text:_c_int00* > SDRAM_BASE .text > RO .const > RO .switch > RO .cinit > RO .rodata > RO .init_array > RO //C++ .sysmem > RW .far > RW .stack > RW .bss > RW .neardata > RW .fardata > RW }
  2. Внял рекомендациям jcxz (за что ему громное спасибо! ). Удалось увеличить производительность на 30...50% (в зависимости от случая). Оказывается, индексная адресация лучше ложится на конвеер, чем инкременты с указателями. И однотипные операции лучше дублировать 2 , 4 или 8 раз. Перестановка действий также может влиять. И ещё можно не присваивать переменным промежуточный результат - компилятор это видит и оптимизирует сам. Инкременторы и питчи задефайнены в константы: SROMBuffer - это закешированная SDRAM на частоте CPU_CLK/3 VRAMBuffer - это L2 на частоте CPU_CLK Вот пример простого отображения: //102 цикла: void PPU16_Tile16B_0(u16 SX,u32 SY,s16 DX,s16 DY,u8 M) { u64 * __restrict SROMOffset=(u64*)&SROMBuffer[((SY*SROM_WIDTH)+SX)<<1]; u64 * __restrict VRAMOffset=(u64*)&VRAMBuffer[((DY*VRAM_WIDTH)+DX)<<1]; _nassert((int)SROMOffset%32==0); _nassert((int)VRAMOffset%2==0); for(int n=0;n<16;n++) { _mem8(&VRAMOffset[0])=_amem8(&SROMOffset[0]); _mem8(&VRAMOffset[2])=_amem8(&SROMOffset[2]); _mem8(&VRAMOffset[1])=_amem8(&SROMOffset[1]); _mem8(&VRAMOffset[3])=_amem8(&SROMOffset[3]); SROMOffset+=SROM_WIDTH>>2; VRAMOffset+=VRAM_WIDTH>>2; } } //96 циклов: ATT void PPU16_Tile16B_0(u16 SX,u32 SY,s16 DX,s16 DY,u8 M) { u64 * __restrict SROMOffset=(u64*)&SROMBuffer[((SY*SROM_WIDTH)+SX)<<1]; u64 * __restrict VRAMOffset=(u64*)&VRAMBuffer[((DY*VRAM_WIDTH)+DX)<<1]; _nassert((int)SROMOffset%32==0); _nassert((int)VRAMOffset%2==0); for(int n=0;n<4;n++) { _mem8(&VRAMOffset[(0*(VRAM_WIDTH>>2))+0])=_amem8(&SROMOffset[(0*(SROM_WIDTH>>2))+0]); _mem8(&VRAMOffset[(0*(VRAM_WIDTH>>2))+1])=_amem8(&SROMOffset[(0*(SROM_WIDTH>>2))+1]); _mem8(&VRAMOffset[(0*(VRAM_WIDTH>>2))+2])=_amem8(&SROMOffset[(0*(SROM_WIDTH>>2))+2]); _mem8(&VRAMOffset[(0*(VRAM_WIDTH>>2))+3])=_amem8(&SROMOffset[(0*(SROM_WIDTH>>2))+3]); _mem8(&VRAMOffset[(1*(VRAM_WIDTH>>2))+0])=_amem8(&SROMOffset[(1*(SROM_WIDTH>>2))+0]); _mem8(&VRAMOffset[(1*(VRAM_WIDTH>>2))+1])=_amem8(&SROMOffset[(1*(SROM_WIDTH>>2))+1]); _mem8(&VRAMOffset[(1*(VRAM_WIDTH>>2))+2])=_amem8(&SROMOffset[(1*(SROM_WIDTH>>2))+2]); _mem8(&VRAMOffset[(1*(VRAM_WIDTH>>2))+3])=_amem8(&SROMOffset[(1*(SROM_WIDTH>>2))+3]); _mem8(&VRAMOffset[(2*(VRAM_WIDTH>>2))+0])=_amem8(&SROMOffset[(2*(SROM_WIDTH>>2))+0]); _mem8(&VRAMOffset[(2*(VRAM_WIDTH>>2))+1])=_amem8(&SROMOffset[(2*(SROM_WIDTH>>2))+1]); _mem8(&VRAMOffset[(2*(VRAM_WIDTH>>2))+2])=_amem8(&SROMOffset[(2*(SROM_WIDTH>>2))+2]); _mem8(&VRAMOffset[(2*(VRAM_WIDTH>>2))+3])=_amem8(&SROMOffset[(2*(SROM_WIDTH>>2))+3]); _mem8(&VRAMOffset[(3*(VRAM_WIDTH>>2))+0])=_amem8(&SROMOffset[(3*(SROM_WIDTH>>2))+0]); _mem8(&VRAMOffset[(3*(VRAM_WIDTH>>2))+1])=_amem8(&SROMOffset[(3*(SROM_WIDTH>>2))+1]); _mem8(&VRAMOffset[(3*(VRAM_WIDTH>>2))+2])=_amem8(&SROMOffset[(3*(SROM_WIDTH>>2))+2]); _mem8(&VRAMOffset[(3*(VRAM_WIDTH>>2))+3])=_amem8(&SROMOffset[(3*(SROM_WIDTH>>2))+3]); SROMOffset+=SROM_WIDTH; VRAMOffset+=VRAM_WIDTH; } } Вариант с поворотом-отражением: //172 цикла //MIRROR_VERTICAL + ROTATE_90 ATT void PPU16_Tile16B_6(u16 SX,u32 SY,s16 DX,s16 DY,u8 M) { u64 * __restrict SROMOffset0=(u64*)&SROMBuffer[((SY*SROM_WIDTH)+SX)<<1]; u64 * __restrict SROMOffset1=SROMOffset0+(SROM_WIDTH>>2); u32 * __restrict VRAMOffset =(u32*)&VRAMBuffer[((DY*VRAM_WIDTH)+DX)<<1]; _nassert((int)SROMOffset0%32==0); _nassert((int)SROMOffset1%32==0); _nassert((int)VRAMOffset%2==0); for(int n=0;n<8;n++) { _mem4(&VRAMOffset[0x0*(VRAM_WIDTH>>1)])=(((u32)((u16) _amem8(&SROMOffset1[0]) ))<<16)|(u32)((u16) _amem8(&SROMOffset0[0]) ); _mem4(&VRAMOffset[0x2*(VRAM_WIDTH>>1)])=(((u32)((u16)(_amem8(&SROMOffset1[0])>>32)))<<16)|(u32)((u16)(_amem8(&SROMOffset0[0])>>32)); _mem4(&VRAMOffset[0x4*(VRAM_WIDTH>>1)])=(((u32)((u16) _amem8(&SROMOffset1[1]) ))<<16)|(u32)((u16) _amem8(&SROMOffset0[1]) ); _mem4(&VRAMOffset[0x6*(VRAM_WIDTH>>1)])=(((u32)((u16)(_amem8(&SROMOffset1[1])>>32)))<<16)|(u32)((u16)(_amem8(&SROMOffset0[1])>>32)); _mem4(&VRAMOffset[0x8*(VRAM_WIDTH>>1)])=(((u32)((u16) _amem8(&SROMOffset1[2]) ))<<16)|(u32)((u16) _amem8(&SROMOffset0[2]) ); _mem4(&VRAMOffset[0xA*(VRAM_WIDTH>>1)])=(((u32)((u16)(_amem8(&SROMOffset1[2])>>32)))<<16)|(u32)((u16)(_amem8(&SROMOffset0[2])>>32)); _mem4(&VRAMOffset[0xC*(VRAM_WIDTH>>1)])=(((u32)((u16) _amem8(&SROMOffset1[3]) ))<<16)|(u32)((u16) _amem8(&SROMOffset0[3]) ); _mem4(&VRAMOffset[0xE*(VRAM_WIDTH>>1)])=(((u32)((u16)(_amem8(&SROMOffset1[3])>>32)))<<16)|(u32)((u16)(_amem8(&SROMOffset0[3])>>32)); _mem4(&VRAMOffset[0x1*(VRAM_WIDTH>>1)])=(((u32)((u16)(_amem8(&SROMOffset1[0])>>16)))<<16)|(u32)((u16)(_amem8(&SROMOffset0[0])>>16)); _mem4(&VRAMOffset[0x3*(VRAM_WIDTH>>1)])=(((u32)((u16)(_amem8(&SROMOffset1[0])>>48)))<<16)|(u32)((u16)(_amem8(&SROMOffset0[0])>>48)); _mem4(&VRAMOffset[0x5*(VRAM_WIDTH>>1)])=(((u32)((u16)(_amem8(&SROMOffset1[1])>>16)))<<16)|(u32)((u16)(_amem8(&SROMOffset0[1])>>16)); _mem4(&VRAMOffset[0x7*(VRAM_WIDTH>>1)])=(((u32)((u16)(_amem8(&SROMOffset1[1])>>48)))<<16)|(u32)((u16)(_amem8(&SROMOffset0[1])>>48)); _mem4(&VRAMOffset[0x9*(VRAM_WIDTH>>1)])=(((u32)((u16)(_amem8(&SROMOffset1[2])>>16)))<<16)|(u32)((u16)(_amem8(&SROMOffset0[2])>>16)); _mem4(&VRAMOffset[0xB*(VRAM_WIDTH>>1)])=(((u32)((u16)(_amem8(&SROMOffset1[2])>>48)))<<16)|(u32)((u16)(_amem8(&SROMOffset0[2])>>48)); _mem4(&VRAMOffset[0xD*(VRAM_WIDTH>>1)])=(((u32)((u16)(_amem8(&SROMOffset1[3])>>16)))<<16)|(u32)((u16)(_amem8(&SROMOffset0[3])>>16)); _mem4(&VRAMOffset[0xF*(VRAM_WIDTH>>1)])=(((u32)((u16)(_amem8(&SROMOffset1[3])>>48)))<<16)|(u32)((u16)(_amem8(&SROMOffset0[3])>>48)); SROMOffset0+=SROM_WIDTH>>1; SROMOffset1+=SROM_WIDTH>>1; VRAMOffset++; } } Горизонтальное отражение: //MIRROR_HORIZONTAL ATT void PPU16_Tile16B_1(u16 SX,u32 SY,s16 DX,s16 DY,u8 M) { /* //102 cycle u64 * __restrict SROMOffset=(u64*)&SROMBuffer[((SY*SROM_WIDTH)+SX)<<1]; u64 * __restrict VRAMOffset=(u64*)&VRAMBuffer[((DY*VRAM_WIDTH)+DX)<<1]; _nassert((int)SROMOffset%32==0); _nassert((int)VRAMOffset%2==0); for(int n=0;n<16;n++) { _mem8(&VRAMOffset[0])=_itoll(_rotl(_loll(_amem8(&SROMOffset[3])),16),_rotl(_hill(_amem8(&SROMOffset[3])),16)); _mem8(&VRAMOffset[1])=_itoll(_rotl(_loll(_amem8(&SROMOffset[2])),16),_rotl(_hill(_amem8(&SROMOffset[2])),16)); _mem8(&VRAMOffset[2])=_itoll(_rotl(_loll(_amem8(&SROMOffset[1])),16),_rotl(_hill(_amem8(&SROMOffset[1])),16)); _mem8(&VRAMOffset[3])=_itoll(_rotl(_loll(_amem8(&SROMOffset[0])),16),_rotl(_hill(_amem8(&SROMOffset[0])),16)); SROMOffset+=SROM_WIDTH>>2; VRAMOffset+=VRAM_WIDTH>>2; } */ //96 cycle u64 * __restrict SROMOffset=(u64*)&SROMBuffer[((SY*SROM_WIDTH)+SX)<<1]; u64 * __restrict VRAMOffset=(u64*)&VRAMBuffer[((DY*VRAM_WIDTH)+DX)<<1]; _nassert((int)SROMOffset%32==0); _nassert((int)VRAMOffset%2==0); for(int n=0;n<4;n++) { _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*0)+0])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*0)+3])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*0)+3])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*0)+2])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*0)+1])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*0)+1])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*1)+0])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*1)+3])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*1)+3])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*1)+2])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*1)+1])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*1)+1])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*2)+0])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*2)+3])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*2)+3])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*2)+2])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*2)+1])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*2)+1])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*3)+0])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*3)+3])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*3)+3])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*3)+2])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*3)+1])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*3)+1])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*0)+1])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*0)+2])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*0)+2])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*0)+3])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*0)+0])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*0)+0])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*1)+1])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*1)+2])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*1)+2])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*1)+3])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*1)+0])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*1)+0])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*2)+1])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*2)+2])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*2)+2])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*2)+3])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*2)+0])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*2)+0])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*3)+1])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*3)+2])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*3)+2])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*3)+3])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*3)+0])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*3)+0])),16)); SROMOffset+=SROM_WIDTH; VRAMOffset+=VRAM_WIDTH; } } Кто смотрели асм-листинг выше, те заметили, что число циклов было на 30 ... 50% больше, чем в последних вариантах. На практике прирост скорости подтвердился также. Особо радует вот это (несколько инструкций впараллель): $C$L164: ; PIPED LOOP PROLOG ; EXCLUSIVE CPU CYCLES: 4 MVK .S1 8800,A5 ; [A_S674] || MVK .S2 800,B8 ; [B_Sb674] || ADD .L2X A18,B18,B24 ; [B_L674] || ADD .L1X A29,B18,A25 ; [A_L674] || LDDW .D1T1 *A20(0),A19:A18 ; [A_D64P] |363| (P) <0,0> || LDDW .D2T2 *B19(0),B7:B6 ; [B_D64P] |363| (P) <0,0> MVK .S2 9600,B17 ; [B_Sb674] || MVK .S1 1600,A17 ; [A_S674] || ADD .L2 B8,B18,B23 ; [B_L674] || ADD .L1X A5,B18,A26 ; [A_L674] || LDDW .D1T2 *A20(16),B9:B8 ; [A_D64P] |367| (P) <0,1> || LDDW .D2T1 *B19(8),A5:A4 ; [B_D64P] |365| (P) <0,1> MVK .S1 10400,A31 ; [A_S674] || MVKH .S2 0xffff0000,B27 ; [B_Sb674] || ADD .L2 B17,B18,B22 ; [B_L674] || ADD .L1X A17,B18,A21 ; [A_L674] || LDDW .D1T1 *A20(8),A17:A16 ; [A_D64P] |365| (P) <0,2> ADDK .S1 -2,A0 ; [A_S674] || ADD .L2 B6,B18,B20 ; [B_L674] || ADD .S2 B16,B18,B21 ; [B_Sb674] || ADD .D2 B29,B18,B25 ; [B_D64P] || ADD .L1X A31,B18,A27 ; [A_L674]
  3. Да, скачал DSPlib, там везде индексный доступ типа такого: float DSPF_sp_dotprod(const float * x, const float * y, const int nx) { int i; float sum = 0; _nassert(nx > 0); _nassert(nx % 8 == 0); _nassert((int)x % 8 == 0); _nassert((int)y % 8 == 0); for(i = 0; i < nx; i++) sum += x[i]*y[i]; return (sum); } Немного рвёт шаблон, так как я предполагал, что индексная адресация более тормозная, чем работа через указатели. Вот наподобие сделал: void PPU16_Tile16B(u16 SX,u32 SY,s16 DX,s16 DY,u8 M) { u64 * __restrict SROMOffset=(u64*)&SROMBuffer[(SY*SPRITE_PITCH)+(SX<<1)]; u64 * __restrict VRAMOffset=(u64*)&VRAMBuffer[((DY*SCREEN_WIDTH)+DX)<<1]; _nassert((int)SROMOffset%32==0); //адрес откуда забираются данные всегда кратен 32 байтам (шаг 16 пикселей) _nassert((int)VRAMOffset%2==0); //адрес куда писать в видеобуфер всегда кратен 2 - точность 1 пиксел for(u32 y=0;y<16;y++) { _mem8(&VRAMOffset[4*y ])=_amem8(&SROMOffset[4*y ]); _mem8(&VRAMOffset[4*y+1])=_amem8(&SROMOffset[4*y+1]); _mem8(&VRAMOffset[4*y+2])=_amem8(&SROMOffset[4*y+2]); _mem8(&VRAMOffset[4*y+3])=_amem8(&SROMOffset[4*y+3]); } } Оно уже 102 цикла делается, вместо 168 что были. Тут не угадаешь, только пробовать и смотреть листинг. На счёт знаний ядра DSP, как повлиять на генерацию кода компилятором?
  4. 8 лет назад я только заканчивал осваивать ARM9, BlackFin и Cyclone-2 FPGA Знать бы ещё как этот код поизменять. Сделал всё возможное от меня зависящее: память в SROM - это SDRAM закешированная на 152 МГц, там исходные данные, с неё читаю сразу 8 байт(4 пикселя) в регистр. Эти данные выровнены на 64 байта (вместо malloc использую memalign для выделения памяти), координаты образца-источника кратны 8 или 16. Память VRAM - это задний видеобуфер. Это кусочек L2 на частоте ядра 456 МГц - туда начитываю в зависимости от случая с атрибутами(отражение-поворот) - иногда удается сразу 8 байт записать, а иногда по 2 байта только. Здесь конечный адрес не выровнен, так как координаты записи могут быть не кратны 8. L2 - отдана на 64 кБ кеш данных, остальные 192 кБ- VRAM и буфер поворота. Отрисовка дисплея сделана через PRU1, с двойной буферизацией - пока DSP готовит новые данные, PRU1 отрисовывает предыдущие, затем меняем местами буфера. Процессор делает ещё поворот на 90 градусов, так как дисплей ведёт развертку вдоль меньшей стороны, и чтобы избежать тиринга изображения и подёргивания, приходится синхронизироваться по VSYNC. И поэтому буфер приходится записывать в дисплей повёрнутым на 90 градусов. Отрисовка в дисплей 171 FPS (переброс с L2 в LCD) , что очень близко к теоретическому максимуму - 176 FPS. Так как разрешение 400*240 *2 байта, шина 8 бит. Запись одного байта в дисплей EMIFA_CLK/3 = 101.3/3 = 33. 76 МГц Вот этих файлов как раз и не хватало для GCC. Попробую поковырять.
  5. Про алгоритмы отрисовки продолжил здесь:
  6. Листинг всей функции: test.asm Как можно ускорить если возможно? Опции компилятора:
  7. Я вам поверил на слово! :) Недавно стал разбираться с конвеерами. Мощная штука. А листинг я не додумался сгенерить, хотя бы по причине того, что в голову не пришло, что GCC не умеет конвееризировать код. :) Кстати, коль уж про конвееры речь пошла, какие опции полезны в настройках TI CC 8.3.5 ? У меня часто пишет в листинге такое: ;* Loop found in file : ..test.c ;* Loop source line : 10 ;* Loop opening brace source line : 11 ;* Loop closing brace source line : 15 ;* Known Minimum Trip Count : 8 ;* Known Maximum Trip Count : 8 ;* Known Max Trip Count Factor : 8 ;* Loop Carried Dependency Bound(^) : 3 ;* Unpartitioned Resource Bound : 2 ;* Partitioned Resource Bound(*) : 3 ;* Resource Partition: ;* A-side B-side ;* .L units 0 0 ;* .S units 1 2 ;* .D units 2 2 ;* .M units 0 0 ;* .X cross paths 0 0 ;* .T address paths 0 0 ;* Logical ops (.LS) 0 0 (.L or .S unit) ;* Addition ops (.LSD) 5 0 (.L or .S or .D unit) ;* Bound(.L .S .LS) 1 1 ;* Bound(.L .S .D .LS .LSD) 3* 2 ;* ;* Searching for software pipeline schedule at ... ;* ii = 3 Did not find schedule ;* ii = 4 Schedule found with 3 iterations in parallel ;* ;* Register Usage Table: ;* +-----------------------------------------------------------------+ ;* |AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA|BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB| ;* |00000000001111111111222222222233|00000000001111111111222222222233| ;* |01234567890123456789012345678901|01234567890123456789012345678901| ;* |--------------------------------+--------------------------------| ;* 0: | ***** | ** | ;* 1: | **** | ** | ;* 2: | ** * | **** | ;* 3: | ** * | ** | ;* +-----------------------------------------------------------------+ ;* ;* Done ;* ;* Loop will be splooped ;* Collapsed epilog stages : 0 ;* Collapsed prolog stages : 0 ;* Minimum required memory pad : 0 bytes ;* ;* Minimum safe trip count : 1 ;* Min. prof. trip count (est.) : 3 ;* ;* Mem bank conflicts/iter(est.) : { min 0.000, est 0.000, max 0.000 } ;* Mem bank perf. penalty (est.) : 0.0% ;* ;* ;* Total cycles (est.) : 8 + min_trip_cnt * 4 = 40 Это плохо или хорошо? На что надо обращать внимание чтобы код работал очень быстро? Пишу вывод графических примитивов размером 8x8 и 16x16 с учётом поворота (на кратные 90 градусов углы) и отзеркаливание по вертикали-горизонтали и оба. Всего 8 случаев вышло - вариант отражения + поворот Код отрисовки тайла 16x16 с поворотами и зеркалингами:
  8. Я брал VAD из кодека Speex на раздербан. Результаты порадовали. Оттудова же взял адаптивный шумоподавитель, очень помогает на MELP2400 или CELP4800 когда идешь вдоль дороги с автомобилями. Всё на C написано и портируемо. Пробовал реализацию на floating point, делать такое на fixed point -задолбаешься оптимизировать BASEOP.
  9. Огромное спасибо за информацию! Да, без пайплайнинга пасти там нечего. Фтпоку GCC, продолжаю работать на TI CC
  10. Приятно был удивлён, что сравнение с нулём привело к генерации более эффективного кода. Задача сводится к отрисовке небольшого квадратного блока 8x8 пикселей с цветом прозрачности. Ниже вариант без прозрачности - в нём за 1 раз рисуются 4 пиксела(8 байтная пересылка). Теперь как цвет прозрачности применить одновременно к 4-м пикселам, чтобы было быстро ? //VRAMOffset - указатель на видеобуфер, может быть невыровненный доступ //SROMOffset - указатель на исходные данные (выровнен на 8 байт) void Draw_Tile8x8(u16 SX,u32 SY,s16 DX,s16 DY) { u64 * __restrict SROMOffset=(u64*)&SROMBuffer[(SY*SPRITE_PITCH)+(SX<<1)]; u64 * __restrict VRAMOffset=(u64*)&VRAMBuffer[((DY*SCREEN_WIDTH)+DX)<<1]; for(u32 y=0;y<8;y++) { _mem8(VRAMOffset++)=_amem8(SROMOffset++); _mem8(VRAMOffset++)=_amem8(SROMOffset++); SROMOffset+=((SPRITE_PITCH>>1)-8)>>2; VRAMOffset+=(SCREEN_WIDTH-8)>>2; } }
  11. Дано: C674x DSP. Цветовое пространство - 16 бит на пиксел (RGB 5:6:5). Надо: реализовать быстрый алгоритм отрисовки с цветом прозрачности. Цвет прозрачности один - либо прозрачно, либо нет. Пока так (неоптимально): for(y=0;y<100;y++) for(x=0;x<100;x++) if(src_color!=colorkey)dst_color=src_color; Советник производительности (perfomance adviser) пишет, что очень мешает условие внутри цикла и рекомендует заменить его на более быстрый алгоритм. Копаю intrinsic для C674x, что-то не могу сообразить из них что-то эффективное. Конкретно, вот это условие: if(src_color!=colorkey)dst_color=src_color; Надо заменить на быстрое выражение, логика которого: ( SRC_COLOR == COLOR_KEY ? ) DST_COLOR : DST_COLOR=SRC_COLOR ; Причём, значение цветового ключа можно выбрать любым, какое будет удобно. Будет только одно значение цветового ключа. Подозреваю, лучшие значения 0 или FFFF. И всё-же как ускориться ?
  12. Всем здравствуйте! Жажда получить более оптимальный код по быстродействию без вылизывания на Асме, побудил меня поискать альтернативный компилятор C/C++ для семейства C674x. И вот что удалось найти: https://sourcery.mentor.com/GNUToolchain/release1882 Скачал, поробовал компильнуть. Всё вроде отлично компилится, но есть пара печальных моментов: 1) Компилятор не знает таких функций как : disable_interrupts() и прочие. Хедеры есть? Или прийдётся лезть в мануал и самому на регистрах писать? 2) Не знает регистров: ICR, IER, ISTP и многих других. Опять самому писать глядя в мануал? Или хедеры где-то всё-же есть? Компилирую так: c6x-uclinux-g++ -march=c674x -O3 -fomit-frame-pointer -ffast-math -fno-rtti -fno-exceptions -Dc6745 -DNDEBUG -IFatFs -IAPI -c FatFs/diskio.c Ещё напрягает -eabi в названии тулчейна. Это только для uC-Linux, Bare Metal этим тулчейном не собрать? Какие есть альтернативы C/C++ от TI ? Интересует семейство DSP C67x, конкретнее C674x.
  13. Актуально. + есть дисплей ардуино шилд на 480x320 с параллельной шиной + SD карта . Пишите на е-маил: repstosw2018 [dоg] gmail [dоt] com или в личку. Плюс новые платы для TMS320C6745.
  14. Актуально. Пишите на е-маил: repstosw2018 [dоg] gmail [dоt] com или в личку. Плюс новые платы для TMS320C6745.
  15. Завершил все работы с игровой консолью BlackPrism Portable. Презентация:
  16. Актуально. Пишите на е-маил: repstosw2018 [dоg] gmail [dоt] com или в личку. Плюс новые платы для TMS320C6745. Подробнее о проекте здесь: http://forum.easyelectronics.ru/viewtopic.php?f=17&t=39290&start=175 Монтажный чертёж, перечень элементов, тестовые прошивки, исходники SDK - по запросу. Схема : Видео в работе:
  17. Если по формулам, то аддитивный или FM-синтез. Yamaha OPL2, OPL3. Если нужна реалистичность звучания - Wavetable с ADSR-огибающей: OPL4. Камешек от Ямахи YMF721- может все типы синтеза аппаратно. Плюс декодирование MIDI-секвенций (MPU401). Использовал этот чип, всем доволен Комплект: Cхема:
  18. Для себя я давно предпочёл фабричный корпус, в который будет устанавливаться разработанная плата. Он из пластика, какого- не знаю, может даже антистатик. Корпус с аналогичного устройства, разработанного китайцами. Это не MIL STD, а "for home or office use" !
  19. Есть один активный коннект - это провод наушников. Он защищён супрессорной матрицей ESDA6V1... Пускай будет. Испытывать преднамерянно пока желания нет - всёравно что вхолостую с парашютом прыгать... зачем лишний раз испытывать судьбу? :) ведь может не раскрыться! AlexandrY уповал на ЭМ-наводки с дисплея, которые будут мешать работе контроллера и памяти. Его прогноз не сбылся. Собственно я вот в каком ключе упомянул вышесказанным.
  20. ставил 350 - не оплавляется паста, только плата сильнее разогревается, так как она поглощает много тепла - 2 плейна по 35 мкм. Сама паста на бумаге плавится при 180. Не рискнул объёмно нагревать плату феном выше 350
  21. Я что-то не понял... Это провокация с целью положить устройство что-ли?. Так есть способ проще - утопить в воде или кувалдой. Вопрос: зачем?
  22. В "домашних условиях" очень трудно проверить качество соединения Termal Pad с множеством via, к тому же непонятно какую температуру выставлять на фене и с какой стороны дуть. А так - влил припой и удостоверился своими глазами, что контакт случился.
  23. Проверил в действии. Всё отлично работает, гипотеза от AlexandrY не сбылась - дисплей не мешает, экран не потребовался.