-
Постов
2 694 -
Зарегистрирован
-
Победитель дней
2
Весь контент repstosw
-
Да, хотелось бы так как при сбросе нажатием кнопки. Пара ног, которые определяют с какого носителя грузиться всегда в одном состоянии и не меняются. С какого адреса у BF532 начинается загрузчик? Попробую сделать прямой переход туда.
-
Да. Штатный загрузчик, который по двум ногам определяет, что надо скопировать код с spi-флешки AT45DB... и передать на него управление
-
ADSP BF532
repstosw опубликовал тема в Сигнальные процессоры и их программирование - DSP
Здравствуйте! Конфигурация: ADSP Blackfin BF532, код выполняется из SDRAM, кеширование включено. Первичная загрузка - из SPI флешки 8-битной (микросхема AT45DB....), затем переход кода в SDRAM. Нужно сбросить процессор, чтобы снова подгрузилась программа из SPI-флешки. (причем именно чтобы снова повторился цикл загрузки с SPI-флешки, ттак как старый образ программы в L1 может быть уже разрушен - стеком, буферами DMA) Вот так - НЕ работает: while(1) __asm__ ("raise 1;"); Спецы, подскажите плиз как сбросить программно? -
Портирую очередную программу написанную на языке C с Win32 (x86) на BlackFin (BF532). При портировании возникла проблема: C-компилятор отказывается компилировать объявление переменных внутри цикла: for(int i=0;i<10;i++) ..... Стоит сделать так - всё работает. int i; for(i=0;i<10;i++) ..... Понимаю, если по всей программе так штук 10-20... Но проблема как раз в том что в программе таких циклов огромное множество! Да и времена старой давности прошли, когда всё было строго. Есть ли у VDSP C compiler ключ какой-нибудь, чтобы понимать объявления переменных внутри цикла? Я знаю, что тот же Keil ARM C compiler поддерживает ключ -C99, при активации которого можно делать такого рода объявления и не только их! Так как? Способ переименования файлос в CPP не предлагать, нужно скомпилировать именно компилером C, а не C++ Всё, разобрался. Проблема была в том что читал протухший мануал C/C++ Compiler and Library Manual for Blackfin® Processors версии VDSP 4.0. В 5.x уже есть опция -c99 :smile3046: OFFTOP: В OpenWatcom C эта опция так и осталась недокументированной: -za99 и -aa
-
Любой участок можно замерить теми же CYCLES, просто вплотную к оптимизации звука ещё не подошел. Кстати, отсутствие мат-сопроцессора в Блекфин меня в свое время очень разочаровало. Есть например приставка SNES, в которой плавучка просто необходима для расчета эффекта полупрозрачности и поворота на произвольный градус. Вот есть STM32 , у них есть мат-сопроцессор, но не более 300 МГц, то не радует. Есть ли камни контроллеров с тактовой от 1 ГГц с FPU и открытой архитектурой? Pi не предлагать, так как закрыта.
-
Ещё обнаружил интересную ситуацию: Visual DSP 5.1.2 даёт рабочий код, а если собрать в VDSP 5.0, то эмулятор зависает в момент когда должен появиться звук. Если не использовать -fp-fast, то обе среды дают рабочий код. Подозреваю, что в 5.0 -fp-fast выполнен через ОПУ и не гарантирует корректной работы с эмуляцией плавучки :)))
-
На самом деле при включенном кешировании арбитраж шины не слишком сильно душит производительность всей системы в целом. Иначе, почему память видеокарт в ПК отображена на общее адресное пространство процессора? В неё тоже можно писать и читать из нее процессором и ПК не тормозит из-за арбитража шины. Понимаю, что видео-карта сама может ворочать в своей памяти и будет быстрее, но доступ со стороны CPU сохранен. Ну и финальный вопрос: вы можете примерно предположить, во сколько раз должна подняться производительность системы, если дисплей перевешать на PPI?
-
В своё время я поостерёгся использовать PPI + RGB-интерфейс дисплея. Показалось, что постоянная отрисовка на дисплей(формирование развертки видео-сигнала) отрицательно скажется на всей работе системы в целом. Не помню чем оттолкнула эта идея, то-ли от того что надо будет выжидать освобождения памяти или ещё чего-то... Давно это было. Вопрос про PPI был в другом: можно ли его настроить на управление контроллером S6E63D6 или тупо видео-сигнал? Хочется чтобы регенерацией экрана занимался именно S6E63D6 , а не ДМА Блекфина через PPI. И шину разгрузить хотелось бы :) Речь идет об этом девайсике: Решил "тряхнуть стариной" и портировать ещё несколько эмуляторов на него
-
Чуть-помогло (+5 FPS), сделал -fast-fp , бинарник чуть-вырос, что свидетельствует о замене либы, что радует. Принял решение временно поиграться с загрузчиком - в нем менял времянки, увы - те что стоят оптимальны по устойчивости и быстродействию. Попытка укоротить setup, hold, write - приводит к плачевным результатам: кривая картинка на дисплее или её отсутствие. Кстати, дисплей буферизован - он подключен к шине через микросхему буфера, чтобы избежать ёмкостного шунтирования SDRAM, которая тоже висит на шине. Если дисплей привешать к PPI, то к нему можно будет обращаться как к массиву точек? Или PPI генерит свою развёртку ? Дисплей PPT9999-A003-06-Q со встроенным контроллером S6E63D6. Вот драйвер для него (тоже сам писал): /* Display PPT9999-A003-06-Q S6E63D6 Display Controller Driver */ #define OLED_Command (*(volatile u16*) 0x20000000) #define OLED_Data (*(volatile u16*) 0x20010000) const u8 Font8x8[2048]= { //тут моноширный шрифт 8x8 пикселей кодировка DOS :) } u16 OLED_Key; //Цвет прозрачности u16 OLED_Back; //Цвет фона void OLED_Register(u8 c,u16 d) { OLED_Command=c; OLED_Data=d; } void OLED_Prepare(void) { OLED_Command=0x23; //Select 18-/16-bit Data Bus Interface OLED_Register(0x03,0x0111); //16-bit Mode OLED_Register(0x10,0x0000); //IC Standby Off OLED_Register(0x05,0x0000); //Display Off OLED_Register(0x18,0x003D); //Frame Rate > 80 Hz OLED_Register(0xF8,0x000F); //VGH = +5V OLED_Register(0xF9,0x000F); //VGL = -5V OLED_Register(0x70,0x2B80); //Gamma Top/Bottom R OLED_Register(0x71,0x3600); //Gamma Top/Bottom G OLED_Register(0x72,0x3E00); //Gamma Top/Bottom B OLED_Register(0x73,0x1F19); //Gamma Top Bottom R1,2 OLED_Register(0x74,0x2214); //Gamma Top Bottom R3,4 OLED_Register(0x75,0x221B); //Gamma Top Bottom G1,2 OLED_Register(0x76,0x1E16); //Gamma Top Bottom G3,4 OLED_Register(0x77,0x241E); //Gamma Top Bottom B1,2 OLED_Register(0x78,0x2617); //Gamma Top Bottom B3,4 SimpleDelay(1000000); OLED_Register(0x05,0x0001); //Display On } void OLED_Rectangle(u16 xs,u8 ys,u16 xe,u8 ye) { OLED_Register(0x35,319-xe); OLED_Register(0x36,319-xs); OLED_Register(0x37,(ys<<8)|ye); OLED_Register(0x20,ys); OLED_Register(0x21,319-xs); OLED_Command=0x22; } void OLED_Clear(u16 Color) { register u32 i; OLED_Rectangle(0,0,319,239); for(i=0;i<320*240;i++) OLED_Data=Color; } void OLED_OutChar(u16 x,u8 y,u8 c,u16 k) { register u32 i; OLED_Rectangle(x<<3,y<<3,(x<<3)+7,(y<<3)+7); for(i=0;i<64;i++) { if(((Font8x8[(c<<3)+(i>>3)]>>(7-(i&7)))&1)) OLED_Data=k; else OLED_Data=OLED_Back; } } void OLED_OutString(u16 x,u8 y,u8* s,u16 k) { register u32 i=0; while(s[i]) { OLED_OutChar(x+i,y,s[i],k); i++; } } void OLED_OutNumber(u16 x,u8 y,u16 n,u16 k) { OLED_OutChar(x ,y,(n/100)%10+'0',k); OLED_OutChar(x+1,y,(n/ 10)%10+'0',k); OLED_OutChar(x+2,y, n %10+'0',k); } void OLED_OutSprite(u16 x,u8 y,u16 w,u8 h,const u8* s) { register u32 i; register u16 c; register u16 *S=(u16*)s; OLED_Rectangle(x,y,x+w-1,y+h-1); for(i=0;i<(w*h);i++) { if((c=S[i])!=OLED_Key) OLED_Data=c; else OLED_Data=OLED_Back; } }
-
Не про то вопрос был. Когда я меняю параметры асинхронного банка (на котором висит дисплей) ПОВТОРНО - новые параметры не вступают в силу! В мануале написано, что не следует менять параметры контроллера шины EBIU именно AMB во время его работы (тоесть когда уже проинициализирован) - мой случай. Тогда как их менять, если по зарез надо? При нажатии на reset ведь как-то работает. Может есть какой-нибудь способ перезагрузить параметры шины? Это плохо! Весь код звуковой системы на плавучке. Эмулятор был написан для x86 на языке Cи, при перекладке кода на Blackfin, будет эмуляция FPU.
-
Попробовал поставить частоту дискретизации 22050 Гц вместо 44100. Скорость всей эмуляции возросла до 75 FPS. Из чего можно сделать вывод, что звуковая система занимает приличный ресурс времени.
-
Так и хочется натянуть свой опыт, да? Не выйдёт. Не мешайте говно с мёдом....... Для начала советую поразмыслить над тем, как эмуляция вашего ЧМ-модулятора относится к: 1) Capcom System QSound 2) Yamaha YM2151 3) OKI6295 Вы хотя бы один из этих чипов эмулировали ? Более на дебаты теоретиков не реагирую. ------------------ А теперь вопросы: 1) Насколько тормозной тип double для BlackFin ? Имеет ли смысл его заменить float ? 2) Каким образом можно изменить параметры растактовки шины EBIU для асинхронного банка, когда он был инициализирован ранее? Тоесть переинициализировать. После того как EBIU запущен, изменить параметры перезаписью в региcтры: EBIU_AMBCTL0 EBIU_AMBCTL1 EBIU_AMGCTL не получается!
-
Если критические участки в программе переписывать на Ассемблере (эмуляция процессоров, эмуляция графики / звука), то производительность должна вырасти. Это выходит за рамки моей задачи, так как было нужно портировать эмулятор (автором которого я НЕ являюсь) на устройство с ADSP BF533. В целом результатом доволен, быстродействие вышло таким: 45 - 55 FPS при эмуляции CPS1 30 - 40 FPS при эмуляции CPS2. При этом показывается каждый кадр, звуковой поток не рвётся (темп плавно понижается). Система CPS слишком наворочена, так как графика/звук у неё заточены под игры(быстрые). И не надо сравнивать какой-то допотопный КР580ВМ80 в связке с убогой графикой (Спектрум небось? ) Ну и вдогонку: телефон с процессором ARM9 800 МГц воспроизводит данный эмулятор хуже (не мой порт), и КПК на 300 МГц ещё хуже! Замерял количество полных отрисовок экрана за 1 секунду (Буфер 320x224x2 из SDRAM + конвертация 16-битной палитры + вывод на дисплей) - 188 раз. Мерял этим: static __inline__ enable_cycles(void) { __asm__ __volatile__ ("R2=SYSCFG;"); __asm__ __volatile__ ("BITSET(R2,1);"); __asm__ __volatile__ ("SYSCFG=R2;"); } static __inline__ disable_cycles(void) { __asm__ __volatile__ ("R2=SYSCFG;"); __asm__ __volatile__ ("BITCLR(R2,1);"); __asm__ __volatile__ ("SYSCFG=R2;"); } static __inline__ start_cycles(void) { __asm__ __volatile__ ("R2=0;"); __asm__ __volatile__ ("CYCLES=R2;"); __asm__ __volatile__ ("CYCLES2=R2;"); } static __inline__ u64 get_cycles(void) { u32 t0,t1; __asm__ __volatile__ ("%0=cycles;%1=cycles2;":"=d"(t0),"=d"(t1)); return t0|((u64)t1<<32); } Это типа троллинг? :santa2: Полный перечень того что делается:
-
Это FPS всего эмулятора, а не экранный FPS: while(!quit) { // эмуляция процессоров Z80, M68020 // эмуляция видео-подсистемы (4 графических слоя) // эмуляция звуковой системы (FM синтезатор + ADPCM + Wav sound*4 канала) // эмуляция системы ввода // эмуляция памяти //эмуляция ROM-set-а // отрисовка на дисплей // вывод звука // считывание клавиш } Вот это всё ВМЕСТЕ - 55 FPS !
-
Сделал DMA по прерываниям. Буфер - 320 пикселов (одна строка) 640 байт в L1, уже сконверченная палитрой(тоже в L1). Даём DMA команду на отрисовку строки, а сами делаем дальше остальные вещи. Прерывание по окончанию пересылки строки снова запускает DMA для новой строки. И так пока экран не отрисуется весь. Код что ниже - рабочий, удаось поднять общую скорость (отрисовка экрана + вся программа) на 15 FPS !!! :rolleyes: Получается, что отрисовка экрана и работа процессора немного распараллелились. Макросы использую, потому что 100% гарантия что с-инлайнится. #define SRC_PITCH 544 #define DST_HEIGHT 224 #define SCR_WIDTH 320 #define SCR_HEIGHT 240 //0xFF800000..0xFF803FFF //L1_DATA_A #define NB (SCR_WIDTH<<1) #define L1_MEMORY 0xFF804000 #define L1_BUF (L1_MEMORY-NB) #define DMA_INIT \ { \ *pMDMA_S1_PERIPHERAL_MAP=0x0040; \ *pMDMA_S1_START_ADDR=(void*)L1_BUF; \ *pMDMA_S1_X_COUNT=(NB>>1); \ *pMDMA_S1_X_MODIFY=2; \ *pMDMA_S1_Y_COUNT=1; \ *pMDMA_S1_Y_MODIFY=0; \ *pMDMA_D1_PERIPHERAL_MAP=0x0040; \ *pMDMA_D1_START_ADDR=(void*)&OLED_Data; \ *pMDMA_D1_X_COUNT=(NB>>1); \ *pMDMA_D1_X_MODIFY=0; \ *pMDMA_D1_Y_COUNT=1; \ *pMDMA_D1_Y_MODIFY=0; \ } \ #define DMA_START \ { \ *pMDMA_S1_CONFIG=WDSIZE_16|DMAEN; \ *pMDMA_D1_CONFIG=WDSIZE_16|WNR|DMAEN|DI_EN; \ } \ #define DMA_STOP \ { \ *pMDMA_S1_CONFIG=0; \ *pMDMA_D1_CONFIG=0; \ } \ extern struct mame_display current_display; u16* src; EX_INTERRUPT_HANDLER(DMA_ISR) { static u16 y=DST_HEIGHT; *pMDMA_D1_IRQ_STATUS=1; y--; if(y) { register u16* buf=(u16*)L1_BUF; register u16 i; for(i=0;i<(NB>>1);i++)*buf++=palette_16bit_lookup[*src++]; src+=(SRC_PITCH-SCR_WIDTH); DMA_START } else { y=DST_HEIGHT; DMA_STOP } } void DMA_Init_Interrupt(void) { *pSIC_IMASK&=0xFFBFFFFF; //Disable MDMA1 interrupt *pSIC_IAR2=(*pSIC_IAR2&0xF0FFFFFF)|0x06000000; register_handler(ik_ivg13,DMA_ISR); *pSIC_IMASK|=0x00400000; //Enable MDMA1 interrupt } int win_init_window(void) { // disable win_old_scanlines if a win_blit_effect is active if (win_blit_effect != 0) win_old_scanlines = 0; DMA_Init_Interrupt(); DMA_INIT OLED_Clear(0x0000); return 0; } void dib_draw_window_DMA(void) { OLED_Rectangle(0,(SCR_HEIGHT-DST_HEIGHT)>>1,SCR_WIDTH-1,((SCR_HEIGHT+DST_HEIGHT)>>1)-1); src=(u16*)(((u32)current_display.game_bitmap->base)+17536+64); register u16* buf=(u16*)L1_BUF; register u16 i; for(i=0;i<(NB>>1);i++)*buf++=palette_16bit_lookup[*src++]; src+=(SRC_PITCH-SCR_WIDTH); DMA_START }
-
Всё сделал как написали, работает исправно, но прироста скорости всёравно нет. Пробовал убрать dma_wait, скорость повышается, но экран отрисовывается на 1/4 и весь трясётся (что и понятно почему). Попробую не ждать, а в обработчик прерывания засунуть вывод на дисплей через DMA. Рабочий код ниже: #ifndef __DMA_H__ #define __DMA_H__ //0xFF800000..0xFF803FFF //L1_DATA_A #define NB 32 #define buf0 (0xFF803FC0-(NB<<1)) #define buf1 (0xFF803FE0- NB ) #define DMA_INIT \ { \ *pMDMA_S1_PERIPHERAL_MAP=0x0040; \ *pMDMA_S1_X_COUNT=(NB>>1); \ *pMDMA_S1_X_MODIFY=2; \ *pMDMA_S1_Y_COUNT=1; \ *pMDMA_S1_Y_MODIFY=0; \ *pMDMA_D1_PERIPHERAL_MAP=0x0040; \ *pMDMA_D1_START_ADDR=(void*)&OLED_Data; \ *pMDMA_D1_X_COUNT=(NB>>1); \ *pMDMA_D1_X_MODIFY=0; \ *pMDMA_D1_Y_COUNT=1; \ *pMDMA_D1_Y_MODIFY=0; \ } \ #define DMA_SEND(buf) \ { \ *pMDMA_S1_START_ADDR=(void*)buf; \ *pMDMA_S1_CONFIG=WDSIZE_16|DMAEN; \ *pMDMA_D1_CONFIG=WDSIZE_16|WNR|DMAEN; \ } \ #define DMA_WAIT while(*pMDMA_D1_IRQ_STATUS&DMA_RUN); #define MEMORY_COPY(dst,src) \ { \ register u16 i; \ register u32* d=(u32*)dst; \ register u32* s=(u32*)src; \ for(i=0;i<(NB>>2);i++) *d++=*s++; \ } \ #define PALETTE_CONVERT(buf) \ { \ register u16 i; \ register u16* c=(u16*)buf; \ for(i=0;i<(NB>>1);i++)*c++=palette_16bit_lookup[*c]; \ } \ #endif void dib_draw_window_DMA(void) { register u16* src=(u16*)(((u32)current_display.game_bitmap->base)+17536+64); register u16 y=DST_HEIGHT; while(y--) { register u16 x=(u16)SCR_WIDTH/(u16)NB; MEMORY_COPY(buf1,src) PALETTE_CONVERT(buf1) src+=(NB>>1); while(x--) { MEMORY_COPY(buf0,src) DMA_SEND(buf1) PALETTE_CONVERT(buf0) src+=(NB>>1); DMA_WAIT MEMORY_COPY(buf1,src) DMA_SEND(buf0) PALETTE_CONVERT(buf1) src+=(NB>>1); DMA_WAIT } src+=(SRC_PITCH-SCR_WIDTH-(NB>>1)); } }
-
Весь цикл программы можно упрощенно представить так: while(!Quit) { эмулируем... рисуем... } Если запустить DMA и отрисовывать построчно, то всеравно прийдется ждать окончания работы DMA чтобы подсунуть ему новую линию с декодированной палитрой при передаче. В момент работы ДМА, процессор всеравно будет брать индексы из SDRAM, а это снова шина. В итоге процессор и ДМА будут рвать шину по кускам.
-
Там очень хитрый буфер. И он "грязный", потому что по-очереди отрисовываются несколько спрайтовых плоскостей (видеосистема Capcom PlaySystem 1/2). Если преобразовывать палитру там, то боюсь всё замедлится в число раз, равное числу плоскостей. Процессор к сожалению будет конвертить палитру, а DMA так же занимать шину во время транзакций. И можно будет авансом заранее сделать не более 1 цикла эмуляции, до того как экран будет полностью не отрисован, иначе пропуск кадра будет что плохо. Проверил работу процедуры. На практике вышло чуть-лучше. Но ненамного. Вот код всей процедуры - пока не вычесал, затронут только внутренний цикл. .section/DOUBLE32 program; .extern _current_display; .extern _palette_16bit_lookup .global _dib_draw_window_asm; _dib_draw_window_asm: [--SP] = (P5:3); P1.L = _current_display+4; P1.H = _current_display+4; P1 = [P1]; P2 = 17600; P0 = 224; I0 = 0; I0.H = 8193; P1 = [P1 + 16]; P5.L = _palette_16bit_lookup; P5.H = _palette_16bit_lookup; P4 = 4; P1 = P1 + P2; [SP + 12] = P1; LOOP CycleYL LC1 = P0; CycleY: LOOP_BEGIN CycleYL; P1 = [SP + 12]; P0 = 80; P3 = [P5]; R5=P3; LOOP CycleXL LC0 = P0; CycleX: LOOP_BEGIN CycleXL; R0=W[P1 + 2] (Z) ; R0=R0<<1 || R1=W[P1 ++ P4] (Z) ; R1=R1<<1 || R2=W[P1 + 2] (Z) ; R2=R2<<1 || R3=W[P1 ++ P4] (Z) ; P0=R3 ; P0=P3+(P0<<1) ; //Preg read after write which requires 4 extra cycles R0=R0+R5 (NS) || R7.L=W[P0] ; I1=R0 ; R1=R1+R5 (NS) || R6.H=W[I1] ; //Dagreg read after write which requires 4 extra cycles I1=R1 ; R2=R2+R5 (NS) || R6.L=W[I1] ; //Dagreg read after write which requires 4 extra cycles I1=R2 ; R3=R3+R5 (NS) || R7.H=W[I1] || [I0]=R6; //Dagreg read after write which requires 4 extra cycles [I0]=R7 ; LOOP_END CycleXL; .P35L13: P0 = [SP + 12]; P1 = 1088; P1 = P0 + P1; //Preg read after write which requires 3 extra cycles [SP + 12] = P1; LOOP_END CycleYL; .P35L14: (P5:3) = [SP++]; RTS; А вот это разочаровало: //Preg read after write which requires 3 extra cycles //Dagreg read after write which requires 4 extra cycles Выходит вся оптимизация и конвеер лесом?? Пока получилось 35 - 40 FPS, в идеале должно быть 60 FPS (частота смены кадров NTSC)
-
Процессор разогнан до 550 МГц. Шина CCLK/3=183 МГц. SDRAM работает на 183 МГц с CAS latency =2. Кеш включен (для кода и данных). Дисплей 7 тактов (setup + write + hold), в эквиваленте 183/7 = 26 МГц. Шина данных 16 бит. Обращение к 32 битам идет подряд как 2 раза по 16 бит, адрес+1. Но та как адресов у контроллера дисплея нет (точнее есть и висит он на самом старшем адресном бите), инкремент адреса не мешает. Это небольшой burst из двух коротких слов :) Сделал 14 строк ассемблера на 4 пикселя. Раньше было 11 строк на 2 пикселя. Ппришлось попарить мозг, пока вышло так (задействовал конвеер Блекфина). Пока не проверял в работе, но компилируется. Эффективность кода возросла на 36% #define PIXEL \ { \ __asm__ volatile (" R0=W[P0++] (Z);"); \ __asm__ volatile ("R0=R0<<1 || R1=W[P0++] (Z);"); \ __asm__ volatile ("R1=R1<<1 || R2=W[P0++] (Z);"); \ __asm__ volatile ("R2=R2<<1 || R3=W[P0++] (Z);"); \ __asm__ volatile ("P3=R3 ;"); \ __asm__ volatile ("P3=P5+(P3<<1) ;"); \ __asm__ volatile ("R0=R0+R5 (NS) || R1.H=W[P3] ;"); \ __asm__ volatile ("I0=R0 ;"); \ __asm__ volatile ("R1=R1+R5 (NS) || R0.L=W[I0] ;"); \ __asm__ volatile ("I1=R1 ;"); \ __asm__ volatile ("R2=R2+R5 (NS) || R0.H=W[I1] ;"); \ __asm__ volatile ("I2=R2 ;"); \ __asm__ volatile ("R3=R3+R5 (NS) || R1.L=W[I2] || [P1]=R0 ;"); \ __asm__ volatile (" [P1]=R1 ;"); \ \ } \ К сожалению объем графических данных не позволяет сделать буфер на строку во внутренней памяти + DMA. Потому что программу писал не я. Это эмуляция аркадных автоматов Capcom Play System 1/2, там палитра больше 256 цветов :) Вот это детище портировал на BF533: https://osdn.net/projects/mamespi/releases/2046 / https://www.zophar.net/mame/caname.html
-
У Блекфина система команд такая, что особо не разбежишься. Всё очень строго, и конвеер там допускает инструкции в строго определенной последовательности. Строковых блочных команд нет вроде. Смотрел внимательно тут: http://microsin.net/programming/dsp/blackf...ence-part1.html http://microsin.net/programming/dsp/blackf...ence-part2.html Максимум получилось избавиться от 2 инструкций - вместо 11 строк кода имею 9: P1 - адрес src, P3 - адрес палитры, P5 - видео-регистр дисплея __asm__ volatile ("R0=W[P1++] (Z);"); \ __asm__ volatile ("P0=R0;"); \ __asm__ volatile ("R0=W[P1++] (Z);"); \ __asm__ volatile ("P2=R0;"); \ __asm__ volatile ("P0=P3+(P0<<1);"); \ __asm__ volatile ("P2=P3+(P2<<1);"); \ __asm__ volatile ("R1.H=W[P0];"); \ __asm__ volatile ("R1.L=W[P2];"); \ __asm__ volatile ("[P5]=R1;"); \
-
По-разному пробовал: //#define PIXEL {OLED_Data_32=(palette_16bit_lookup[src[1]]<<16)|palette_16bit_lookup[src[0]];src+=2;} //#define PIXEL {OLED_Data_32=palette_16bit_lookup[*src++];OLED_Data_32=palette_16bit_lookup[*src++];} Выходит так: 1 LOOP_BEGIN .P38L6L; 2 R0 = W[P1 + 2] (Z); 3 P0 = R0; 4 R0 = W[P1 ++ P5] (Z); 5 P2 = R0; 6 P0 = P3 + (P0<<1); 7 R0.L = W[P0]; 8 P0 = P3 + (P2<<1); 9 R1 = R0 << 16 || R0 = W[P0] (Z); 10 R0 = R1 | R0; 11 [P4] = R0; 12 LOOP_END .P38L6L; 1 LOOP_BEGIN .P38L6L; 2 R0 = W[P1++] (Z); 3 P2 = R0; 4 P2 = P4 + (P2<<1); 5 R0 = W[P2] (Z); 6 [P5] = R0; 7 R0 = W[P1++] (Z); 8 P2 = R0; 9 P2 = P4 + (P2<<1); 10 R0 = W[P2] (Z); 11 [P5] = R0; 12 LOOP_END .P38L6L; Не особо вижу разницы, да и код на внешний вид действительно неплотный. Вот это : R1 = R0 << 16 || R0 = W[P0] (Z); - параллельное выполнение команд? LDM R0!, {R1-R8};сорри за ARM wink.gif и получит burst-чтение SDRAM Это 8 порций по 32 бита подряд за одно чтение? Есть ли такая фишка в Блекфинах? :rolleyes: :rolleyes: :rolleyes: У Intel-ловских процессоров есть подобное с mmx- и xmm- регистрами: 8 байт за раз переслать можно аналогично!
-
Согласен, иначе следующие PIXEL при if()else... не попадут под условие. Попробую вернуть внутренний цикл и посмотреть что сделает компилятор(асм- листинг). Пробовал процедуру отрисовки скопировать в L1 Code SRAM (64K) из SDRAM. Вот так: memcpy((void*)0xFFA00000, (const void*)Draw_Screen,0x8000); //скопировал 32 килобайта (с запасом, точный размер функции в map-файле) // 0xFFA00000 - 0xFFA0FFFF Code SRAM (64K) При передаче управления туда - зависает. Передаю управление так: #define CALL(Address) (*(void(*)(void)) Address)(); //Вызов функции по её адресу CALL(0xFFA00000) Что не так? Как правильно грузить данный участок памяти кода L1 Code SRAM ? (от кеширования этот участок свободен). Есть ли #pragma в Visual DSP позволяющая сделать отдельные фуккции позиционно-независимыми? (position independent) ? Насколько оправдано размещать отдельно код процедуры отрисовки во внутренней памяти, если включено кеширование для SDRAM (I cache + D cache) ? Приложение большое - около 2 МБайт.
-
Быстро, в смысле уменьшить время перекидывания буфера на экран. Перерисовка экрана полная. Посмотрел листинг функции на ассемблере, мой опыт не позвояет сказать насколько оптимально делает VDSP++, листинг приложил. Знающих в ассебмлере, прошу глянуть листинг - оцените насколько неоптимально или оптимально сделал компилятор свою работу? Если же слабые места будут, то буду копать ассемблер BF. asm.txt Это два пиксела по 16 бит каждый.
-
BF533 отрисовка на дисплей
repstosw опубликовал тема в Сигнальные процессоры и их программирование - DSP
Здравствуйте. Использую ADSP BF533 + SDRAM + OLED Display (подключен к EBIU 16 бит). Программа загружена в SDRAM, кэширование включено: для данных и программ, политика write back. Дисплей не прокеширован. Периодически нужно отрисовывать кадр на дисплей, как можно быстрее. Видеопамять дисплея - 16 бит на пиксел, адрес автоматически увеличивается на +1 пиксел после отрисовки точки. Есть буфер в котором строистя изображение - источник. Кодировка цветов через палитру. Приемником выступает сам дисплей. Палитру засунул в L1_DATA_B, чтобы ускорить доступ к ней (попиксельно идет обращение). Буфер источника находится в SDRAM (кеширована). За один присест сразу рисую 2 пиксела по 16 бит, по сути формирую 32-битное обращение к памяти дисплея: #define OLED_Data_32 (*(volatile u32*) 0x20010000) Хотя он подключен к 16-битной шине. Фрагмент кода: //u8, u16, u32 - char, short и long соответственно 1 2 4 байта UINT16* palette_16bit_lookup=(UINT16*)0xFF900000; //L1_DATA_B 16KB Тут палитра #define SRC_PITCH 544 /* Ширина источника */ #define DST_HEIGHT 224 /* Высота приемника */ #define SCR_WIDTH 320 /* Ширина дисплея */ #define SCR_HEIGHT 240 /* Высота дисплея */ #define OLED_Data_32 (*(volatile u32*) 0x20010000) /* Это регистр данных дисплея с автоинкрементом адреса, подключен к EBIU Blackfin - разрядность 16 бит */ #define PIXEL OLED_Data_32=(palette_16bit_lookup[src[1]]<<16)|palette_16bit_lookup[src[0]];src+=2; /* выводим сразу 2 пиксела(по 16 bit) на дисплей, цвет берем из палитры */ #define PIXELLAST OLED_Data_32=(palette_16bit_lookup[src[1]]<<16)|palette_16bit_lookup[src[0]];src+=(SRC_PITCH-SCR_WIDTH+2); /* последние 2 пиксела */ void Draw_Window(struct BITMAP *bitmap) //Отправка буфера на дисплей { register u16* src=(u16*)(((u32)bitmap->base)+17536+64); //Стартовый адрес источника register u32 y=DST_HEIGHT; OLED_Rectangle(0,(SCR_HEIGHT-DST_HEIGHT)>>1,SCR_WIDTH-1,((SCR_HEIGHT+DST_HEIGHT)>>1)-1); //Задаёт прямоугольную область 320x224 по центру дисплея (сам дисплей 320x240) while(y--) //цикл по Y, цикл по X развернут на 320 точек (160 слов) { PIXEL /* 159 раз */ PIXEL PIXEL /* ... */ PIXEL PIXEL PIXELLAST /* 160-й раз */ } } Цикл по X развернут макросами для ускорения. Компилировал это дело в Visual DSP++ 5.1.2 - пробовал такую оптимизацию: Speed 100, Interprocedural optimization, Frame-pointer optimization. Код работает как нужно , но подозреваю, что можно сделать быстрее! Дает ли прирост скорости 32-битное обращение к регистру данных дисплея, когда он подключен к 16-битной шине? Фактически это 2 операции подряд по 16 бит с увеличением адреса (не используются). Как можно сделать ещё быстрее? Рассмотрю любые способы: от изменения алгоритма, до системного управления процессором (кеширование, выравнивание). Пробовал изменить тайминги шины EBIU, ничего не меняется. Как можно пере-инициализировать контроллер асинхронной шины, когда он уже работает?