|
NIOSII - Странный глюк, тестирую модуль для SOPC и не понимаю :( |
|
|
|
Jul 13 2007, 14:36
|
Знающий
   
Группа: Свой
Сообщений: 518
Регистрация: 12-04-07
Из: Санкт-Петербург
Пользователь №: 26 997

|
Здравствуйте! Наконец-то, после долгого чтения мануалов я написал свой модуль для SOPC. Написал небольшую программку для NIOSII с целью протестировать модуль и столкнулся с очень странным для меня глюком. Сначала о модуле: Два порта, мастер и слейв. У слейва три регистра: CNTRL, STATUS и ADR. CNTRL: 0-ой бит – go. NIOSII выставляет этот бит, модуль начинает работать, на следующий такт бит автоматически сбрасываетя. STATUS: 2-ой бит – error, этот бит выставляется, если произошла ошибка. 1-ый бит – busy, выставлен пока модуль работает. 0-ой бит – done, выставлется когда работа модуля закончена. ADR – в этот регистр NIOSII записывает адрес. Работает модуль (по моей задумке, по крайней мере) так: выставляется бит go, логика модуля по этому биту считывает данные извне (свитчи на плате) и передает их мастер-порту. Мастерпорт, получив эти данные, записывает их по адресу из регистра ADR слейва, потом читает данные оттуда же. Если данные совпадают, то работа модуля заканчивается, если не совпадают, то выставляется бит error. Код программы для NIOSII: Код #include <stdlib.h> #include "alt_types.h" #include <stdio.h> #include <unistd.h> #include "system.h" #include "sys/alt_irq.h" #include "altera_avalon_pio_regs.h" #include "TestM_regs.h"
int ButFlag=0;
static void handle_button_interrupts(void* context, alt_u32 id) { *((alt_u8*)context)=1; IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUT_BASE, 0); }
static void init_button_pio() { IOWR_ALTERA_AVALON_PIO_IRQ_MASK(BUT_BASE, 0x1); IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUT_BASE, 0x0); alt_irq_register( BUT_IRQ, (void*) &ButFlag, handle_button_interrupts ); }
int main() { alt_u32 led=0xAAAA; init_button_pio();
while(1) { if (ButFlag){ IOWR_TESTM_ADR(TESTM_0_BASE,(int)&led); IOWR_TESTM_CTRL(TESTM_0_BASE,0x1); //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! while (IORD_TESTM_STATUS(TESTM_0_BASE) & 0x1); IOWR_ALTERA_AVALON_PIO_DATA(LEDR_BASE,led); ButFlag=0; } } return 0; } Суть глюка: если прогу запустить как Run As, то LEDR (лампочки на плате) выводят 0xAAAA, а не то, что выставлено свичами. При этом бит ошибки не выставляется. Если запустить как Debug as NIOSII Hardware, то начинаются странности. Если на любой строчке до помеченной восклицательными знаками включительно сделать step (F5 или F6), то все прекрасно работает, выводится именно то, что на свичах. Если же с самого начала дебагинга сделать resume (F8) или же поставить брейкпоинт за помеченной строчкой, то прога ведет себя как при Run As. В чем суть глюка я понять не могу решительно. Адрес в ADR пишется, бит done выставляется, error – нет. Грешил на SDRAM, но проект делал на основе альтеровского примера ниоса для этой самой платы (Starter kit - cyclon 2). Попробовал снизить частоту со 100 до 50 – не помогло. На всякий случай прикладываю файлы головного модуля, модуля pll и reset. Подскажите, в чем может быть дело и где вообще искать решение? PS: Я еще только начинаю. Если кому-то вдруг будет не лень просмотреть мои верилоговские файлы и указать всякие ошибки перехода от C к Verilog? поправить стиль и т.п., то я буду очень благодарен!!! Прикладываю файлы: TESTM.v, TESTM_L.v, TESTM_M.v, TESTM_S.v - верилоговские файлы, описывающие сам модль. TestM_regs.h -файл с макросами для работы с модулем. sdram_pll.v и reset_delay.v - соответственно названию. NT.v - головной модуль проекта. Кстати, пытался добавить квартовский архив проекта, но "не имеете прав на добавление файла с разрешением" qar. Почему?
Прикрепленные файлы
TestM.v ( 1.54 килобайт )
Кол-во скачиваний: 58
TestM_L.v ( 759 байт )
Кол-во скачиваний: 48
TestM_M.v ( 3.06 килобайт )
Кол-во скачиваний: 71
TestM_S.v ( 2.27 килобайт )
Кол-во скачиваний: 59
NT.v ( 6.22 килобайт )
Кол-во скачиваний: 191
Reset_Delay.v ( 1.09 килобайт )
Кол-во скачиваний: 59
SDRAM_PLL.v ( 14.88 килобайт )
Кол-во скачиваний: 87
|
|
|
|
|
Jul 13 2007, 17:02
|
carpe manana
  
Группа: Свой
Сообщений: 321
Регистрация: 2-06-05
Пользователь №: 5 659

|
Ну во-первых, вы не приложили модуль syst. Во-вторых, лучше бы вы все файлы в одном архиве выложили рядом, чтобы разом скачать, для желающих. Самое главное - вы систему моделировали в моделсиме до синтеза? Программа небольшая, много времени не займет. Общие замечания: много лишнего верилога в регистрах, о чем вам должен был сказать синтезатор. пример: если вы записываете в регистр, достаточно просто написать Код if (write) my_reg <= writedata; и совсем не надо дописывать Код else my_reg <= my_reg; Читать тяжело. Сейчас я попробую посмотреть, что внутри, если получится - напишу. А может вы просто в тесте ошибку сделали, и проверяете while (IORD_TESTM_STATUS(TESTM_0_BASE) & 0x1); вместо while (IORD_TESTM_STATUS(TESTM_0_BASE) & 0x2); Но тогда у вас все висеть должно намертво. И еще я бы led объявил как volatile, но это вы должны были в дебагере в ассемблере увидеть, что чтениz не происходит.
|
|
|
|
|
Jul 13 2007, 17:24
|
Знающий
   
Группа: Свой
Сообщений: 518
Регистрация: 12-04-07
Из: Санкт-Петербург
Пользователь №: 26 997

|
Цитата(id_gene @ Jul 13 2007, 20:20)  Ну во-первых, вы не приложили модуль syst. Во-вторых, лучше бы вы все файлы в одном архиве выложили рядом, чтобы разом скачать, для желающих. Про syst.v не сообразил - прикладываю тут. Про "рядом" - тоже не сообразил. Сейчас выложу. Цитата(id_gene @ Jul 13 2007, 20:20)  Самое главное - вы систему моделировали в моделсиме до синтеза? Программа небольшая, много времени не займет. Нет.  Поскольку моделсимом пока не владею.  он в очереди на освоение. Цитата(id_gene @ Jul 13 2007, 20:20)  Общие замечания: много лишнего верилога в регистрах, о чем вам должен был сказать синтезатор. Спасибо. Синтезатор не ругался (варингами, по крайне мере). А он по умолчанию будет считать, что в противном случае значение не меняется? Это гуд, буду знать. Просто у альтеры в примере именно так сделано, а другого образца я не имею - у нас на работе никто верилогом не владеет.  Цитата(id_gene @ Jul 13 2007, 21:02)  А может вы просто в тесте ошибку сделали, и проверяете while (IORD_TESTM_STATUS(TESTM_0_BASE) & 0x1); Упс. Просто я в течение дня ковырялся и уходя с работы взял файлы впопыхах. Разумеется, там Код while (!(IORD_TESTM_STATUS(TESTM_0_BASE) & 0x1)) Цитата(id_gene @ Jul 13 2007, 21:02)  И еще я бы led объявил как volatile, но это вы должны были в дебагере в ассемблере увидеть, что чтениz не происходит. Хочу уточнить, какое именно чтение не происходит? Можете вкратце объяснить, как компилятор среагирует на volatile? Может, действительно тут дело? Хотя, тогда совершение одного шага в дебагере не должно делать код работающим, но делает. Что ввергает меня в шок.  Вот файлы: nt.qar - http://ifolder.ru/2658520 - квартуcoвский архив проекта. software - http://ifolder.ru/2658543 - архив програмного проекта (вдруг там в настройках syslib дело?). nt.rar - http://ifolder.ru/2658813 - архив всей папки с проектом, включая и модуль и софт.
Прикрепленные файлы
syst.v ( 343.28 килобайт )
Кол-во скачиваний: 95
|
|
|
|
|
Jul 13 2007, 18:04
|
carpe manana
  
Группа: Свой
Сообщений: 321
Регистрация: 2-06-05
Пользователь №: 5 659

|
Цитата(RHnd @ Jul 13 2007, 21:24)  Можете вкратце объяснить, как компилятор среагирует на volatile? Например вы читаете в цикле переменную, которая у вас меняется независимо от программы (аппаратным контроллером). int a = 0; while (a); Такую конструкцию компилятор оптимизирует и выкидыает, потому что не увидит в ней смысла, пока вы не объявите переменную как voltile. Тогда компилятор честно вставит чтение. Как раз ваш случай. Зачем процессору читать второй раз переменную led из памяти, если она уже хранится в стеке или в регистре. Успел покопаться только в вашем модуле, глобальных проблем в нем не вижу. Попробуйте в дебагере определить адрес переменной led и монитором памяти (он там внизу запрятан) посмотреть реальное содержание памяти в этом месте до и после программы. Общие замечания по верилогу: на мой взгляд, слишком много лишних регистров. В каких-то случаях это может быть оправдано, особенно, когда вам нужно все конвееризировать, и сильно не хватает скорости, или когда вы хотите избавиться от лишних переключений в нерабочем состоянии, но вся эта братия занимет ресурсы и межсоединения. Вот посмотрите, как я переписал ваш модуль. Вы к этому тоже со временем привыкнете, начнете понимать, что и где можно сократить. Я там все три модуля в один записал, чтобы файлы не плодить. Синхронизация внешних данных происходит всегда, а не только по стробу старта. Если это критично, то не надо там плодить еще одну машину состояний, просто поставьте два регистра после go_reg, и пользуйтесь ими. Чтение слейва синхронное, т.е. данные идут из регистра. можно урезать до асинхронного, выиграть такт, но удлиннить путь. Чтение контрольного регистра я выкинул, потому что полезной информации вы там не найдете. Машина состояний теперь имеет три состояния. Для увеличения скорости можно добавить еще одно состояние после чтения, чтобы принять прочитанные данные в регистр, и только потом сравнивать с сохраненным значением. Это разгрузит логику данных по чтению, и вы получите большую частоту. Все вышесказанное мое имхо и, возможно, слегка упрощено. Критика принимается. Ушел.
Прикрепленные файлы
my_sm.v ( 4.51 килобайт )
Кол-во скачиваний: 172
|
|
|
|
|
Jul 13 2007, 20:10
|
Знающий
   
Группа: Свой
Сообщений: 518
Регистрация: 12-04-07
Из: Санкт-Петербург
Пользователь №: 26 997

|
Цитата(RHnd @ Jul 13 2007, 22:29)  Пошел смотреть исправление модуля. Большое спасибо за помощь!!! Посмотрел модуль. Узнал много нового о верилоге, даже несколько вопросов возникло.  Помню, читал и слышал, что при использовании if или case нужно описывать все ветви, иначе могут быть траблы. Из вашего кода сделал вывод, что при использование триггеров (когда идет обработка по фронту) это не так, полное описание всех ветвей требуется только при описании логики (always @*). Правильно? Есть вопрос вот по этому куску кода: Код // asynchronous read version // does not hold the value when s_chipselect deasserted always @* case (s_address) 2'b01 : s_readdata = {29'h0, reg_status}; 2'b10 : s_readdata = reg_address; default : s_readdata = {29'h0, reg_status}; // required in comb logic endcase s_readdata объявлен как reg [31:0]. Мне казалось, что если объявлен как reg, то обрабатываться должен как триггер - по фронту. А здесь формируется логика. Был неправ? И вопрос, который меня давно мучит - почему здесь стоит = а не <=? Пробовал заменить, но в RTL Viewer разницы не увидел. Концепция двух разных присваиваний для меня совсем новая, так до сих пор разницу между ними и не осознал. Что касается volatile - вспомнил, что в дебагере добавлял watch &led и смотрел как сам адрес (проверить, что в регистр модуля пишется), так и его содержимое. Оно, вроде, не менялось. Но все равно в понедельник попробую. А вам большой  PS: Странно, что примеры альтеры "не оптимальны". Может, они писались с учетом совместимости с более ранними стандартами verilog? Хотелось бы для развития посмотреть примеры хорошего кода - как надо и как принято. Наилучшим, наверное, было бы посмотреть курс каких-нибудь лабораторных по verilog с примерами качественного исполнения. Если кто-нить может поделиться подобным, то буду очень признателен! r h n d (сбака) m a i l . r u
|
|
|
|
|
Jul 14 2007, 07:30
|
carpe manana
  
Группа: Свой
Сообщений: 321
Регистрация: 2-06-05
Пользователь №: 5 659

|
Цитата(RHnd @ Jul 14 2007, 00:10)  Помню, читал и слышал, что при использовании if или case нужно описывать все ветви, иначе могут быть траблы. Из вашего кода сделал вывод, что при использование триггеров (когда идет обработка по фронту) это не так, полное описание всех ветвей требуется только при описании логики (always @*). Правильно? Правильно. Цитата Есть вопрос вот по этому куску кода: ... s_readdata объявлен как reg [31:0]. Мне казалось, что если объявлен как reg, то обрабатываться должен как триггер - по фронту. А здесь формируется логика. Был неправ? Неправ. Единственное различие между reg и wire в том, что reg можно назначать только в блоке always, а wire только через assing. Поскольку case в комбинаторике можно использовать только внутри always блока, то здесь как раз объявелн reg. Есть еще блок initial. В нем вы можете использовать только reg для назначений, но если очень надо wire, то для можно поставить force/release. Цитата И вопрос, который меня давно мучит - почему здесь стоит = а не <=? Поищите в интернете примеры, под рукой нет ни одного. Общее правило таково: в регистрах используются неблокирующие <=, в комбинаторных always блоках - блокирующие =. Цитата Что касается volatile - вспомнил, что в дебагере добавлял watch &led и смотрел как сам адрес (проверить, что в регистр модуля пишется), так и его содержимое. Еще можно в кэш попасть. То есть опять фактического чтения из памяти не произойдет. тут еще можно поразбираться. ps нормальные примеры у Альтеры. Оптимальность в данном случае - такая тонкая штука. pps кстати, мой верилог можно еще больше упростить, например assign m_write = state_machine_reg[0]; и так далее.
|
|
|
|
|
Jul 14 2007, 17:21
|
Знающий
   
Группа: Свой
Сообщений: 518
Регистрация: 12-04-07
Из: Санкт-Петербург
Пользователь №: 26 997

|
Цитата(id_gene @ Jul 14 2007, 11:30)  Есть еще блок initial. В нем вы можете использовать только reg для назначений, но если очень надо wire, то для можно поставить force/release. Блок initial, вроде, только для моделирования? Он ведь не синтезируемый? Цитата(id_gene @ Jul 14 2007, 11:30)  Еще можно в кэш попасть. То есть опять фактического чтения из памяти не произойдет. тут еще можно поразбираться. Тоже возможно. а как бы мне это проверить? кроме как отключить кеш и собрать заново - идей нет. Поправка - вроде же можно писать мимо кеша выставляя старший бит адресса? Что-то такое видел в документации, но никогда не пользовался. Цитата(id_gene @ Jul 14 2007, 11:30)  ps нормальные примеры у Альтеры. Оптимальность в данном случае - такая тонкая штука. Не, нормальные, рабочие, но они, например, при объявлении модуля перечисляют module A(B,C); input B; output C;
|
|
|
|
|
Jul 16 2007, 15:45
|
Знающий
   
Группа: Свой
Сообщений: 518
Регистрация: 12-04-07
Из: Санкт-Петербург
Пользователь №: 26 997

|
Итак, дело оказалось в data cache. Сначала попробовал volatile, но не помогло. После этого отключил нафиг кеш, пересобрал ниос - заработало. Тонкое место найдено. Какие способы решения ситуации я для себя открыл (ну, кроме отключения кеша  ): 1) Вариант, на котором я и остановился: Код alt_u32* p_led=(alt_u32*)alt_uncached_malloc(4); *p_led=0xAAAA; init_button_pio();
while(1) { if (ButFlag){ IOWR_TESTM_ADR(TESTM_0_BASE,(int)p_led); IOWR_TESTM_CTRL(TESTM_0_BASE,0x1); while (!(IORD_TESTM_STATUS(TESTM_0_BASE) & 0x1)); IOWR_ALTERA_AVALON_PIO_DATA(LEDR_BASE,*p_led); ButFlag=0; } } alt_uncached_free((void*)p_led); 2) Второй вариант, вызвавший у меня затруднения. Код volatile alt_u32 led=0xAAAA; alt_u32* p_led; init_button_pio();
while(1) { if (ButFlag){ IOWR_TESTM_ADR(TESTM_0_BASE,(int)&led); IOWR_TESTM_CTRL(TESTM_0_BASE,0x1); while (!(IORD_TESTM_STATUS(TESTM_0_BASE) & 0x1)); p_led=(alt_u32*)(((int)&led)|0x80000000); // p_led=(alt_u32*)alt_remap_uncached((void*)&led,4); IOWR_ALTERA_AVALON_PIO_DATA(LEDR_BASE,*p_led); ButFlag=0; } } Что мне странно: вариант Код p_led=(alt_u32*)(((int)&led)|0x80000000); работает прекрасно, а вот вариант Код p_led=(alt_u32*)alt_remap_uncached((void*)&led,4); не работает. Хотя, по дебагеру значение p_led в обоих случаях одинаковое. В чем тут дело? Может, я не правильно описание функции alt_remap_uncached понял и некорректно ее использую?
|
|
|
|
|
Jul 16 2007, 16:29
|
Знающий
   
Группа: Свой
Сообщений: 518
Регистрация: 12-04-07
Из: Санкт-Петербург
Пользователь №: 26 997

|
Цитата(vetal @ Jul 16 2007, 20:17)  1.Для задач общения с периферией существуют специальные команды stwio и ldwio, которым чихать на кэш. Эти команды доступны через макросы IOWR_32DIRECT и IORD_32DIRECT. Т.е. мне надо просто заменить макросы в header? Я свой писал на основе альтеровских, а у них эти макросы (которые direct) не использовались. Цитата(vetal @ Jul 16 2007, 20:17)  2. Похоже что вы пытаетесь работать с регистрами как с памятью. А можно подробнее для тех кто в танке? Цитата(vetal @ Jul 16 2007, 20:17)  3. установка старшего бита адреса как раз и отключает все примочки и преврfщает команду IOWR в IOWR_DIRECT. Для этого я старший бит и устанавливаю.
|
|
|
|
|
Jul 16 2007, 16:51
|

Гуру
     
Группа: Модераторы
Сообщений: 2 095
Регистрация: 27-08-04
Из: Россия, СПб
Пользователь №: 553

|
Цитата(RHnd @ Jul 16 2007, 20:29)  Т.е. мне надо просто заменить макросы в header? Я свой писал на основе альтеровских, а у них эти макросы (которые direct) не использовались. Да, замените iowr на iowr_direct для доступа к регистрам модуля. Цитата А можно подробнее для тех кто в танке? Подробнее чем там не опишу http://www.altera.com/literature/lit-nio2.jsp Более близко - http://www.altera.com/literature/hb/nios2/n2cpu_nii51017.pdf (847к) Смотреть и описание инструкций stw/stwio и описание макросов в файле io.h Код #define IOWR_32DIRECT(BASE, OFFSET, DATA) \ __builtin_stwio (__IO_CALC_ADDRESS_DYNAMIC ((BASE), (OFFSET)), (DATA)) Цитата Для этого я старший бит и устанавливаю. Это не очень удобно при работе с hal ))(см. выше)
|
|
|
|
|
Jul 16 2007, 16:59
|
Знающий
   
Группа: Свой
Сообщений: 518
Регистрация: 12-04-07
Из: Санкт-Петербург
Пользователь №: 26 997

|
Спасибо, завтра попробую заменить макросы. Надеюсь, в новые проблемы не вляпаюсь.  И все же, чем p_led=(alt_u32*)(((int)&led)|0x80000000) от p_led=(alt_u32*)alt_remap_uncached((void*)&led,4) отличается?
|
|
|
|
|
Jul 16 2007, 17:26
|
Знающий
   
Группа: Свой
Сообщений: 518
Регистрация: 12-04-07
Из: Санкт-Петербург
Пользователь №: 26 997

|
Цитата(vetal @ Jul 16 2007, 21:15)  Практически ничем, она подставляет в старший бит адреса 1. Тогда странно, что получается разный результат. Сейчас сообразил, что у нас какое-то недопонимание. Итак, модулю дается указатель на переменную - адрес в сдрам. Модуль по этому адресу пишет. Проблема в том, что когда ниос после работы модуля обращается к этой переменной, то получает не записанное модулем значение из сдрам, а значение из кеша. Как мне тут может помочь замена макросов? Макросы ведь относятся к работе модуля, а он и так работатет корректно, мне же надо получить значение переменной из сдрам в обход кеша. Или я что-то не то говорю? Так и не понял, почему вы считаете, что я пытаюсь работать с регистрами как с памятью? Заранее спасибо за ответы. Я ведь еще только учусь.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|