Перейти к содержанию
    

помогите написать конечный автомат правильно

Привет всем,

 

Я новичок в HDL, до этого были только обычные языки типа c/c++...

 

Задача такая: на вход подается 3 сигнала нажатия кнопки, клок, ресет и сигнал старта видеокадра (длительностью несколько клоков с периодом "очень много клоков")

По фронту с одной из кнопок необходимо начать считать кадры до 4-х и выдавать номер кадра наружу. В момент прихода 5-го кадра нужно сбросить счетчик. В момент прихода первого кадра с момента нажатия необходимо выдать наружу номер нажатой кнопки и держать его, пока не начнется 5-й кадр. Еще необходимо сформировать дополнительный сигнал старта кадра, который будет выдаваться только пока идет счет кадров.

 

В итоге получился такой код:

module switch_ctrl(
    input ffc, //кнопка 1
    input cold, //кнопка 2
    input hot, //кнопка 3
    input frame_start, //старт кадра
    output reg [3:0]switch_enable, //какая кнопка была нажата: 0х01(никакая) 0х02 (ffc) 0х04(cold) 0x08 (hot)
    output reg [3:0]frame_number, //номер кадра
    output reg frame_start_out, //доп сигнал старта кадра
    input clk,
    input resetn
    );
    
    localparam FRAME_AVG = 3; //количество кадров для счета
        reg [7:0] frm_cntr; //внутренний счетчик кадров
        localparam M_NORMAL = 4'b0001, //идентификаторы кнопки
                        M_FFC = 4'b0010,
                        M_COLD = 4'b0100,
                        M_HOT = 4'b1000;
    reg[3:0] SELECTED_MODE; // регистр индентификатора кнопки
    reg[4:0] STATE; // регистр состояния
    localparam S_IDLE = 0, //идентификаторы состояния
                    S_EN_CNTR = 1,
                    S_COUNTING = 2,
                    S_CNTR_DONE = 3;
                    
    wire frame_start_pulse;
    one_pulse frame_start_i(.clk(clk), .resetn(resetn), .thing(frame_start), .pulsy(frame_start_pulse));
                    
    always @(posedge clk or negedge resetn) 
    begin
    if( resetn == 1'b0) //resetting
    begin
        SELECTED_MODE <= M_NORMAL;
        STATE <= S_IDLE;
        frm_cntr <= FRAME_AVG;
        switch_enable <= M_NORMAL;
        frame_start_STATE <= 0;
        frame_number <= 0;
        frame_start_out <= 0;
    end else begin
            case(STATE)
                S_IDLE: //ожидание нажатия кнопки
                begin
                        if(ffc)
                        begin
                            SELECTED_MODE <= M_FFC;
                            STATE <= S_EN_CNTR;
                        end
                        
                        if(cold)
                        begin
                            SELECTED_MODE <= M_COLD;
                            STATE <= S_EN_CNTR;
                        end     
                                       
                        if(hot)
                        begin
                            SELECTED_MODE <= M_HOT;
                            STATE <= S_EN_CNTR;
                        end    
                end
    
                S_EN_CNTR: //кнопка была нажата, ожидаем фронта сигнала старта кадра
                begin
                    if(frame_start_pulse)
                    begin
                        STATE <= S_COUNTING;
                        switch_enable <= SELECTED_MODE;
                        frame_start_out <=1; 
                    end                      
                end
    
                S_COUNTING: //считаем кадры
                begin
                    if(frame_start_pulse)
                    begin
                        if(frm_cntr) begin
                            frm_cntr <= frm_cntr - 1;
                            frame_number <= frame_number + 1;
                            frame_start_out <= 1;
                        end else begin //если счетчик кадров дошел до нуля, то возвращаемся в ожидание
                            STATE <= S_IDLE;
                            frm_cntr <= FRAME_AVG;
                            switch_enable <= M_NORMAL;
                            SELECTED_MODE <= M_NORMAL;
                            frame_number <= 0;
                        end
                    end else begin
                        frame_start_out <= 0;                                                   
                    end
                end
            endcase
            
        end 
end                
endmodule

module one_pulse(input clk, input resetn, input thing, output pulsy); //детектор фронта сигнала старта кадра
reg thing_dly;
assign pulsy = thing & ~thing_dly;

    always @(posedge clk or negedge resetn)
    begin
        if(!resetn)
        thing_dly <= 1'b0;
        else
        thing_dly <= thing; 
    end          
endmodule

 

Я работаю в Vivado и тут есть 5 типов симуляции: Behavioral, Post-Synthesis Functional, Post-Synthesis Timing, Post-Implementation Functional и Post-Implementation Timing.

 

В бехэворе все норм:

post-59873-1419533220_thumb.png

А вот в Post-Synthesis Functional вообще все глухо:

post-59873-1419533428_thumb.png

В Post-Synthesis Timing снова все хорошо (если не считать на один клок увеличившейся задержки, но это не критично)

post-59873-1419533551_thumb.png

И в Post-Implementation Timing тоже неплохо, если не считать скачков (glitches?) на выходах...

post-59873-1419533718_thumb.png

 

В Post-Implementation Functional снова все глухо на выходах...

 

Что не так с моим кодом и как его переделать так, чтобы в любой симуляции он работал правильно?

И что это за выбросы на выходах в Implementation? это артефакт симуляции, или надо ставить дополнительные регистры на выходы? (хотя вроде они там и так стоят...)

 

Спасибо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если отличаются результаты симуляций, это может быть результатом внезапных для тебя оптимизаций.

 

Советую посмотреть на схему в синтезе и имплементации, попробовать понять что пропало и кто виноват.

 

Если найти виновника удастся, можно вбить костыль в нужную строчку:

(* dont_touch = "true" *)

Подробнее:

http://www.xilinx.com/support/documentatio...o-synthesis.pdf

 

Но лучше разобраться в причинах и сделать как надо.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

S_IDLE: //ожидание нажатия кнопки
               begin
                       if(ffc)
                       begin
                           SELECTED_MODE <= M_FFC;
                           STATE <= S_EN_CNTR;
                       end

                       if(cold)
                       begin
                           SELECTED_MODE <= M_COLD;
                           STATE <= S_EN_CNTR;
                       end     

                       if(hot)
                       begin
                           SELECTED_MODE <= M_HOT;
                           STATE <= S_EN_CNTR;
                       end    
               end

Мне чего-то эта штука глаз мозолит, попробуйте тут else цепочкой добавить. В железе не поверяли?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У вас внешний сигнал frame_start синхронен с клоком clk? если нет, то ваш детектор фронта написан неверно. Нужно так:

module one_pulse(input clk, input resetn, input thing, output pulsy); //детектор фронта сигнала старта кадра

reg thing_dly;
reg [1:0] thing_sync;

assign pulsy = thing_sync[1] & ~thing_dly;
    always @(posedge clk)
    begin
        if(!resetn)
            thing_dly <= 1'b0;
            thing_sync <= 2'd0;
        else
            thing_sync <= (thing_sync << 1) | thing;
            thing_dly <= thing_sync[1];
    end          
endmodule

И не используйте конструкцию типа always @(posedge clk or negedge resetn), пользуйтесь always @(posedge clk) с синхронным резетом. Если резет не синхронен с clk, сделайте его синхронным по аналогии с кодом, приведенным выше. Виды сброса, дока. Вот на форуме была полезная тема про метастабильность и синхронизацию метастабильность

 

А по поводу конечных автоматов, во первых likeasm сказал правильно, у вас в певом состояние 1 регистр используется в 3-ч схемах одновременно, что невозможно :laughing: . Ну и все регистры, которые задействованы в конечном автомате, должны быть проинициализированы в стартовом состоянии.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В Post-Implementation Functional снова все глухо на выходах...

 

Что не так с моим кодом и как его переделать так, чтобы в любой симуляции он работал правильно?

И что это за выбросы на выходах в Implementation? это артефакт симуляции, или надо ставить дополнительные регистры на выходы? (хотя вроде они там и так стоят...)

Тут скорее вопрос в том, чем отличаются и зачем существуют Behavioral, Post-Synthesis Functional, Post-Synthesis Timing, Post-Implementation Functional и Post-Implementation Timing

Вот вам зачем все 5 понадобились? Только потому что они есть?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2likeasm: в железе работает...

2serjj: frame_start с клоком синхронен (в модуле симуляции его фронт точно совпадает с фронтом клока), хотя когда сделал по вашему, то заработало в Post-Synthesis Functional! Правда задержка выросла аж на 2 клока...

а вот добавление else к первым 3-м ифам ситуации не меняет...

2Torpeda: Да я пока пытаюсь во всем разобраться, чтоб ожидания совпадали с реальностью, так сказать. А то потом глюки повылазят, задолбаюсь отлаживать.

А режимы эти значат вроде как простую вещь: Behavioral - симуляция на уровне RTL, Post-Synthesis - симуляция на уровне синтезированного проекта, Post-Implementation - симуляция на уровне реализации с учетом особенностей железа. Ну и timing - значит учет задержек распространения сигнала в логике (а в Post-Implementation еще и с учетом задержек в роутинге) По крайней мере я так понимаю.

Но что именно в данной ситуации приводит к разным результатам...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Задержка в 2 клока вам критична? :rolleyes: Просто нужно добавить компенсацию задержки на данные, зато все будет синхронно. Вообще лучше сразу делать синхронный дизайн, в дальнейшем может быть ситуация, когда входной сигнал и клок уже не будут синхронны, а код будет считаться рабочим, ведь он работал когда-то. Это порождает ошибки, которые приходится искать очень долго.

Первые 3 if может и не делают погоду, просто так писать точно не стоит.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ну да, можно всегда по данным задержку увеличить, это не проблема конечно...

Т.е. все эти ифы исполняются как бы одновременно? И если вдруг сработает больше одного, то в регистры SELECTED_MODE и STATE запись будет идти синхронно? И что в итоге окажется в этих регистрах?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2Torpeda: Да я пока пытаюсь во всем разобраться, чтоб ожидания совпадали с реальностью, так сказать. А то потом глюки повылазят, задолбаюсь отлаживать.

А режимы эти значат вроде как простую вещь: Behavioral - симуляция на уровне RTL, Post-Synthesis - симуляция на уровне синтезированного проекта, Post-Implementation - симуляция на уровне реализации с учетом особенностей железа. Ну и timing - значит учет задержек распространения сигнала в логике (а в Post-Implementation еще и с учетом задержек в роутинге) По крайней мере я так понимаю.

Но что именно в данной ситуации приводит к разным результатам...

ОК Это всё равно что сказать - Названиями отличаются. А смысл в них какой?

Чем уровень синтезированного проекта (Post-Synthesis) отличается от RTL? Логика в них идентичная описана...

Чем реализация "с учетом особенностей железа" (Post-Implementation) отличается от уровня синтезированного проекта (Post-Synthesis)? Что там за "особенности появились"?

 

Просто без ответа на эти вопросы дальше пытаться решить проблему "со странными результатами симуляций" не выйдет.....

В чём корень проблемы отличия разных симуляций ответа нет...вы сейчас какие-то синхронизаторы, задержки, else добавляете в надежде, что "неизвестная" проблема самоустраниться...

с таким-же успехом можно и в бубен постучать...

 

Я вот пока вижу только проблему в интерпретации результатов

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Получается что вы хотите от него, что бы они выполнялись одновременно. Для 1 регистра используется одновременно разная логика, это неверно. Если вы например пишите

cnt <= cnt + 1'b1;

вы не можете потом через пару строк записать еще и

if (cnt == 'd32) cnt <= cnt + 2'd2;

использование регистра должно быть описано в одном месте, так как вы описываете физически одну цепочку.

Соберите проект так как вы написали первый раз, посмотрите в RTL Viewer, как он собрался, особенно какая логика сформирована вокруг регистра STATE.

Затем перепишите правильно, посмотрите как он собрался в данном случае. Это полезно будет изучить. Вообще, когда начинаете использовать новую языковую конструкцию, полезно ее проверить в RTL Viewer и отдельно в симуляторе, как она себя ведет при различных воздействиях, а в вашем случае все конструкции пока новые :rolleyes: .

И я бы пока не увлекался различными вариантами моделирования. Достаточно поведенческое моделирование по RTL коду и собственно проверка в железе, можну с помощью Signaltap/Chipscope. Это дольше, но пока для вас будет нагляднее. Если код работает логически (в Modelsim все ок), а в Signaltap вы видите проблемы/несоответствия, значит есть какие-то аппаратные/имплементационные/физические косяки. Что бы их моделировать, нужно знать какие они бывают, а лучше всего это понимается на железе в живую. Потратите больше времени (аппаратная отладка все таки), но при этом разберетесь. А уже потом можно пробовать облегчать себе жизнь моделирование пост-синтез, пост-фиттер. Как то так :laughing:

Изменено пользователем serjj

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

И я бы пока не увлекался различными вариантами моделирования. Достаточно поведенческое моделирование по RTL коду и собственно проверка в железе, можну с помощью Signaltap/Chipscope. Это дольше, но пока для вас будет нагляднее. Если код работает логически (в Modelsim все ок), а в Signaltap вы видите проблемы/несоответствия, значит есть какие-то аппаратные/имплементационные/физические косяки. Что бы их моделировать, нужно знать какие они бывают, а лучше всего это понимается на железе в живую. Потратите больше времени (аппаратная отладка все таки), но при этом разберетесь. А уже потом можно пробовать облегчать себе жизнь моделирование пост-синтез, пост-фиттер. Как то так :laughing:

 

ябы так сказал...

обычно отличие Post-Implementation Timing от железа не наблюдается

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...