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

Не работает модуль на verilog

Доброго всем времени суток!

Прошу меня сильно не пинать, Verilog начал изучать совсем недавно. Модуль не хочет работать ни в симуляторе, ни в железе( Код программы, RTL и скрин симуляции прилагаются, могу скинуть исходный код. Проект собирается в Quartus II 9.1, ПЛИС cyclone III.

Код:

module MEM_CONTROLLER
(
    input   clk, cs,
    input   [15:0] data_in,
    output  [15:0] data_out,
    output  reg [3:0] addr,
    output  wr
);
    reg [15:0] data_out_reg;
    reg [2:0] state;
    reg b_write;    //Если 1 - то записываем данные
    reg wr_reg;        

    parameter S0 = 0, S1 = 1, S2 = 2, S3 = 3, S4 = 4, S5 = 5, S6 = 6;

    always @ (posedge clk) 
    begin
        case (state)
            
            //---------------------------
            // Ждем спад 1 cs
            //---------------------------
            S0:
                if (cs==0)
                    state <= S1;
                else
                    state <= S0;
            //---------------------------
            // Фронт 1 cs, заносим адрес в регистр addr
            // Если старший бит = 1 - то записываем данные в RAM,
            // иначе - читаем
            //---------------------------
            S1:
                if (cs)
                    begin
                        case (data_in[2:0])
                            3'b001  : addr <= 4'b0001;
                            3'b010  : addr <= 4'b0010;
                            3'b011  : addr <= 4'b0100;
                            3'b100  : addr <= 4'b1000;
                            default : addr <= 4'b0000;
                        endcase
                        
                        b_write <= data_in[15]? 1'b1:1'b0;
                        state <= S2;
                    end
                else
                    state <= S1; 
            //---------------------------
            // Ждем спад 2 cs            
            //---------------------------
            S2:
                if (cs==0)
                    state <= S3;
                else
                    state <= S2;
            //---------------------------
            // Ждем фронт 2 cs
            //---------------------------
            S3:
                if (cs)
                    if (b_write)
                        begin
                            data_out_reg[15:0] <= data_in[15:0];
                            state <= S4;
                        end
                    else
                        state <= S0;    //Читаем данные (выводим их на data_out)
                else
                    state <= S3;
            //---------------------------
            // Ждем установки addr
            // Устанавливаем wr = 1
            //---------------------------        
            S4:
            begin
                wr_reg <= 1;
                state <= S5;
            end
            //---------------------------
            // Сбрасываем wr
            //---------------------------        
            S5:
            begin    
                wr_reg <= 0;
                state <= S0;
            end
            //---------------------------
        endcase
    end

    assign data_out[15:0] = data_out_reg[15:0];
    assign wr = wr_reg;

endmodule

RTL:

RTL.png

Waveform:

simulation.png

 

В симулиции по логике там где стоит маркер должен происходить переход в состояние S2, но ничего не происходит(

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


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

Прошу меня сильно не пинать, Verilog начал изучать совсем недавно. Модуль не хочет работать ни в симуляторе, ни в железе

1. Я бы посоветовал проводить симуляцию не тем симулятором, который поставляется вместе с Quartus, а в таких симуляторах, как например, Modelsim или AtiveHDL. У всех есть бесплатные версии с ограничениями.

2. Начните описывать автоматы 3 классическими always блоками :

Первый блок синхронный - переключение состояний автомата.

Второй блок комбинационный - вычисление следующего состояния автомата.

Третий блок комбинационный - выходня логика автомата.

И лишь тогда, когда Вы научитесь правильно описывать автоматы таким стилем, только тогда переходите к другим стилям описания автомата. Сейчас Вы выбрали самый сложный стиль описания, где допустить ошибку очень и очень просто. А найти её, да ещё при использовании альтеровского симулятора, очень сложно.

3. Ну и присвойте нормальные имена состояниям автомата вместо:

parameter S1 = 0, S1 = 1, S2 = 2, S3 = 3, S4 = 4, S5 = 5, S6 = 6;

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

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


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

Модуль не хочет работать ни в симуляторе, ни в железе

Не вижу ничего криминального, сам так пишу. Но вот какой смысл писать эти S0 S1,2...? Просто числа, либо идентификаторы. А тут можно просто числами ограничиться было.

Первое что заметил, в Verilog все имена зависят от высоты букв, поэтому разумеется что CS и cs это разные переменные для Verilog и в S2 мы так никогда и не попадем, хотя я не вижу код тестбенча, чтобы утверждать точно.

Далее, симулятор показывает белиберду в state.S0..N, почему нельзя просто вывести state ввиде числа и там было бы всё ясно и однозначно.

В общем, нужен опыт и всё станет хорошо.

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


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

2. Начните описывать автоматы 3 классическими always блоками :

Первый блок синхронный - переключение состояний автомата.

Второй блок комбинационный - вычисление следующего состояния автомата.

Третий блок комбинационный - выходня логика автомата.

И лишь тогда, когда Вы научитесь правильно описывать автоматы таким стилем, только тогда переходите к другим стилям описания автомата. Сейчас Вы выбрали самый сложный стиль описания, где допустить ошибку очень и очень просто. А найти её, да ещё при использовании альтеровского симулятора, очень сложно.

А можно чуть подробнее? Для реализации state-машины я использовал стандартный шаблон автомата Мура:

module four_state_moore_state_machine
(
    input    clk, in, reset,
    output reg [1:0] out
);

    // Declare state register
    reg        [1:0]state;

    // Declare states
    parameter S0 = 0, S1 = 1, S2 = 2, S3 = 3;

    // Output depends only on the state
    always @ (state) begin
        case (state)
            S0:
                out = 2'b01;
            S1:
                out = 2'b10;
            S2:
                out = 2'b11;
            S3:
                out = 2'b00;
            default:
                out = 2'b00;
        endcase
    end

    // Determine the next state
    always @ (posedge clk or posedge reset) begin
        if (reset)
            state <= S0;
        else
            case (state)
                S0:
                    state <= S1;
                S1:
                    if (in)
                        state <= S2;
                    else
                        state <= S1;
                S2:
                    if (in)
                        state <= S3;
                    else
                        state <= S1;
                S3:
                    if (in)
                        state <= S2;
                    else
                        state <= S3;
            endcase
    end

endmodule

Но здесь всего 2 блока: синхронный (Determine the next state) и комбинационный - вычисление следующего состояния автомата (Output depends only on the state). О каком третьем блоке Вы говорите? Насчет имен состояний полностью согласен - напишу что-нибудь более вразумительное.

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

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


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

Сейчас Вы выбрали самый сложный стиль описания, где допустить ошибку очень и очень просто.
Я придерживаюсь прямо противоположного взгляда. Ничего простого и удобного в размазывании КА по нескольким процессам не вижу.

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


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

Я придерживаюсь прямо противоположного взгляда. Ничего простого и удобного в размазывании КА по нескольким процессам не вижу.

У Вас опыта гораздо больше :biggrin:.

Согласен, что несколько неудобно, т.к описание такого КА получается достаточно громоздким. Но при разделении автомата на 3 процесса - меньше шансов наделать ошибок, особенно это важно для начинающих. Считаю, что сначала надо научиться делать "классически" и "неудобно" - и когда будет полное понимание того, что происходит при описании автомата и в какую схему в итоге это выливается(да и вообще важно понимать что схемотехнически представляет собой цифровой автомат), тогда можно писать удобным для себя стилем, опять-же с полным пониманием зачем и почему.

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


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

По совету Flip-fl0p переделал state-машину на 2 always-блока:

module MEM_CONTROLLER
(
    input    clk, cs,
    input     [15:0] data_in,
    output     reg[15:0] data_out,
    output     reg[3:0] addr,
    output     reg wr
);
    reg [15:0] data_out_reg;
    reg [3:0] addr_reg;
    reg b_write;    //Если 1 - то записываем данные
    reg wr_reg;        
    
    initial 
    begin
        data_out_reg = 15'b0;
        addr_reg = 4'b0;
    end
    
    
    reg    [2:0] state;
    parameter S0 = 0, S1 = 1, S2 = 2, S3 = 3, S4 = 4;


    // Output depends only on the state
    always @ (state, data_out_reg, addr_reg, data_in) 
    begin
        case (state)
            S0,S1,S2,S3:
            begin
                data_out[15:0] = data_out_reg[15:0];
                addr[3:0] = addr_reg[3:0];
                wr = 1'b0;
            end
            S4:
            begin
                data_out[15:0] = data_in[15:0];
                addr[3:0] = addr_reg[3:0];
                wr = 1'b1; 
            end    
            
            default:
            begin
                data_out[15:0] = 15'b0;
                addr[3:0] = 4'b0;
                wr = 1'b0;
            end 
        endcase
    end


    always @ (posedge clk) 
    begin
        case (state)
            
            //---------------------------
            // Ждем спад 1 cs
            //---------------------------
            S0:
                if (cs==0)
                    state <= S1;
                else
                    state <= S0;
            //---------------------------
            // Ждем фронт 1 cs, заносим адрес в регистр addr
            // Если старший бит в адресе = 1 - то записываем данные,
            // иначе - читаем
            //---------------------------
            S1:
                if (cs)
                    begin
                        case (data_in[2:0])
                            3'b001  : addr_reg <= 4'b0001;
                            3'b010  : addr_reg <= 4'b0010;
                            3'b011  : addr_reg <= 4'b0100;
                            3'b100  : addr_reg <= 4'b1000;
                            default : addr_reg <= 4'b0000;
                        endcase
                        
                        b_write <= data_in[15]? 1'b1:1'b0;
                        state <= S2;
                    end
                else
                    state <= S1; 
            //---------------------------
            // Ждем спада 2 cs            
            //---------------------------
            S2:
                if (cs==0)
                    state <= S3;
                else
                    state <= S2;
            //---------------------------
            // Ждем фронт 2 cs
            //---------------------------
            S3:
                if (cs)
                    if (b_write)
                        state <= S4;
                    else
                        state <= S0;    //Читаем данные (выводим их на data_out)
                else
                    state <= S3;
            //---------------------------
            // Устанавливаем wr = 1
            //---------------------------        
            S4:
                state <= S0;
            //---------------------------
        endcase
    end

endmodule

 

В результате получилась более компактная и понятная RTL-схема:

RTL_2.png

 

И симуляция частично поправилась:

simulation_2.png

Только теперь значение data_out меняется только на момент состояния S4, при этом не сохраняя измененное значение ( Как это можно поправить?

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


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

Только теперь значение data_out меняется только на момент состояния S4, при этом не сохраняя измененное значение ( Как это можно поправить?

Начать действовать последовательно и осмысленно.

Во-первых, если вы отлаживаете FSM, то нужно и смотреть FSM (регистр state), и входные сигналы, которые влияют на переход из одного состояния в другое.

Соответвствие выходов состоянию отладите позже.

Но если вы считаете, что автомат проходит по состояниям верно, то отлажвайте выходы. В вашем коде, в состояниях, кроме S4 data_out равно значению регистра, который инициализируется, но присваиваний которому не производится, т.е. он неизменный на протяжении работы системы, потому и data_out не изменяется. А в состоянии S4 сигналу data_out присваивается другое значение. То есть, всё работает так, как написано, и если вы хотите другого поведения, то его надо определить и описать в коде.

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

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


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

Только теперь значение data_out меняется только на момент состояния S4, при этом не сохраняя измененное значение ( Как это можно поправить?

Потому-что data_out у вас мультиплексор, который в состоянии S4: выдает то, что на входе (data_in) :

 

                data_out[15:0] = data_in[15:0];
                addr[3:0] = addr_reg[3:0];
                wr = 1'b1;

 

а в остальных состояниях выдает нули.

 

            default:
            begin
                data_out[15:0] = 15'b0;
                addr[3:0] = 4'b0;
                wr = 1'b0;
            end

 

Делать надо немного по-другому. В состоянии S4 выдается сигнал разрешения записи в регистр:

            S4:
            begin
                    write_ena = '1';
            end

 

И где-то описать эти регистры(Verilog только читаю, а не пишу на нем. Мог допустить ошибки. Передал суть):

 

    always @ (posedge clk) 
    begin
        if (write_ena)
            begin
                data_out[15:0] = 15'b0;
                addr[3:0] = 4'b0;
                wr = 1'b0;
            end
        
    end

 

Вот тут посмотрите : http://www.asic-world.com/tidbits/verilog_fsm.html

P.S. А почему такая старая версия Quartus ? Последняя версия, поддерживающая Cyclone III - Quartus 13.1.

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


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

to Sprite Посмотрел я на времянку и мозг отказал минут на 5 - как машина может находиться одновременно в нескольких состояниях? Там вообще мусор должен быть на моделировании - начальное состояние не определено - либо сброс добавьте, либо начальное условие при инициализации. Или это картинка не моделирования, а сигнал тап?

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


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

Ошибся я немного. Переписал state-машину:

    // Output depends only on the state
    always @ (state, data_out, addr_reg, data_in) 
    begin
        case (state)
            S0,S1,S2,S3:
            begin
                data_out[15:0] = [b]data_out[15:0];[/b]
                addr[3:0] = addr_reg[3:0];
                wr = 1'b0;
            end
            S4:
            begin
                data_out[15:0] = data_in[15:0];
                addr[3:0] = addr_reg[3:0];
                wr = 1'b1; 
            end    
            
            default:
            begin
                data_out[15:0] = 15'b0;
                addr[3:0] = 4'b0;
                wr = 1'b0;
            end 
        endcase
    end

Вместо data_out_reg[15:0] нужно было делать присвоение data_out[15:0] < data_out[15:0]. Естественно все заработало) Только вылезла целая куча варнингов, типа:

Warning (10240): Verilog HDL Always Construct warning at MEM_CONTROLLER.v(27): inferring latch(es) for variable "data_out", which holds its previous value in one or more paths through the always construct

Как я понял квартус ругается на наличие latch, но именно так я и планировал.

 

RTL-схема:

MEM_CONTROLLER.png

 

и правильный waveform:

 

Simulation_3.png

 

Конечно, некрасиво с варнингами, буду думать как устранить.

 

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


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

Как я понял квартус ругается на наличие latch, но именно так я и планировал.

А Вы читали, что я Вам писал ?

Latch - в 99% случаев это ошибка. Вы пытаетесь в комбинационном блоке сохранить значения. Ну Qurtus и сделал Вам защелку, как Вы и просили его.

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


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

Как я понял квартус ругается на наличие latch, но именно так я и планировал.

А Вы читали, что я Вам писал ?

Latch - в 99% случаев это ошибка. Вы пытаетесь в комбинационном блоке сохранить значения. Ну Qurtus и сделал Вам защелку, как Вы и просили его.

 

Поправил) Вынес защелку в отдельный блок:

module MEM_CONTROLLER

(

input clk, cs,

input [15:0] data_in,

output [15:0] data_out,

output [3:0] addr,

output wr

);

reg [15:0] data_out_reg;

reg [3:0] addr_reg;

reg b_write; //Если 1 - то записываем данные

reg wr_reg;

 

initial

begin

data_out_reg = 15'b0;

addr_reg = 4'b0;

end

 

 

reg [2:0] state;

parameter S0 = 0, S1 = 1, S2 = 2, S3 = 3, S4 = 4, S5 = 5;

 

always @ (posedge clk)

begin

case (state)

 

//---------------------------

// Ждем спад 1 cs

//---------------------------

S0:

if (cs==0)

state <= S1;

else

state <= S0;

//---------------------------

// Ждем фронт 1 cs, заносим адрес в регистр addr

// Если старший бит в адресе = 1 - то записываем данные,

// иначе - читаем

//---------------------------

S1:

if (cs)

begin

case (data_in[2:0])

3'b001 : addr_reg <= 4'b0001;

3'b010 : addr_reg <= 4'b0010;

3'b011 : addr_reg <= 4'b0100;

3'b100 : addr_reg <= 4'b1000;

default : addr_reg <= 4'b0000;

endcase

 

b_write <= data_in[15]? 1'b1:1'b0;

state <= S2;

end

else

state <= S1;

//---------------------------

// Ждем спад 2 cs

//---------------------------

S2:

if (cs==0)

state <= S3;

else

state <= S2;

//---------------------------

// Ждем фронт 2 cs, устанавливаем wr_reg

//---------------------------

S3:

if (cs)

if (b_write)

state <= S4;

else

state <= S0; //Читаем данные (выводим их на data_out)

else

state <= S3;

//---------------------------

// Устанавливаем wr_reg

//---------------------------

S4:

begin

wr_reg <= 1'b1;

state <= S5;

end

//---------------------------

// Сбрасываем wr_reg

//---------------------------

S5:

begin

wr_reg <= 1'b0;

state <= S0;

end

//---------------------------

endcase

end

 

//---------------------------

// Блок-защелка данных

//---------------------------

always @ (posedge clk)

begin

if (state == S4)

data_out_reg[15:0] = data_in[15:0];

end

 

//---------------------------

assign data_out = data_out_reg;

assign addr = addr_reg;

assign wr = wr_reg;

//---------------------------

endmodule

 

RTL-схема:

 

MEM_CONTROLLER_4.png

 

И нерабочий Waveform:

 

Simulation_4.png

 

В итоге пришел к самому первому варианту( Один большой плюс: варнинги исчезли))

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

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


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

//---------------------------
// Блок-защелка данных
//---------------------------
always @ (posedge clk) 
begin
  if (state == S4)
    data_out_reg[15:0] = data_in[15:0];
end

Это - не защёлка, а 15 параллельных триггеров:

always @ (posedge clk) 
    data_out_reg = state == S4 ? data_in : data_out_reg;

А, вообще, давайте Ваш проект (тем более, что он небольшой) сюда (с тестбенчем, конечно): будет время - можно повозиться.

 

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


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

Это - не защёлка, а 15 параллельных триггеров:

always @ (posedge clk) 
    data_out_reg = state == S4 ? data_in : data_out_reg;

А, вообще, давайте Ваш проект (тем более, что он небольшой) сюда (с тестбенчем, конечно): будет время - можно повозиться.

 

Проект Во вложении. entity - test3.qpf Собирал в Quartus II 9.1, использовал для теста встроенный симулятор (файл test3.vwf)

cyclone_III.rar

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

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


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

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

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

Гость
Ответить в этой теме...

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

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

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

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

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

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