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

Не работает модуль на 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:

Waveform:


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

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


Ссылка на сообщение
Поделиться на другие сайты
Цитата(Sprite @ May 10 2018, 07:33) <{POST_SNAPBACK}>
Прошу меня сильно не пинать, Verilog начал изучать совсем недавно. Модуль не хочет работать ни в симуляторе, ни в железе

1. Я бы посоветовал проводить симуляцию не тем симулятором, который поставляется вместе с Quartus, а в таких симуляторах, как например, Modelsim или AtiveHDL. У всех есть бесплатные версии с ограничениями.
2. Начните описывать автоматы 3 классическими always блоками :
Первый блок синхронный - переключение состояний автомата.
Второй блок комбинационный - вычисление следующего состояния автомата.
Третий блок комбинационный - выходня логика автомата.
И лишь тогда, когда Вы научитесь правильно описывать автоматы таким стилем, только тогда переходите к другим стилям описания автомата. Сейчас Вы выбрали самый сложный стиль описания, где допустить ошибку очень и очень просто. А найти её, да ещё при использовании альтеровского симулятора, очень сложно.
3. Ну и присвойте нормальные имена состояниям автомата вместо:
Код
parameter S1 = 0, S1 = 1, S2 = 2, S3 = 3, S4 = 4, S5 = 5, S6 = 6;

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

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


Ссылка на сообщение
Поделиться на другие сайты
Цитата(Sprite @ May 10 2018, 07:33) <{POST_SNAPBACK}>
Модуль не хочет работать ни в симуляторе, ни в железе

Не вижу ничего криминального, сам так пишу. Но вот какой смысл писать эти S0 S1,2...? Просто числа, либо идентификаторы. А тут можно просто числами ограничиться было.
Первое что заметил, в Verilog все имена зависят от высоты букв, поэтому разумеется что CS и cs это разные переменные для Verilog и в S2 мы так никогда и не попадем, хотя я не вижу код тестбенча, чтобы утверждать точно.
Далее, симулятор показывает белиберду в state.S0..N, почему нельзя просто вывести state ввиде числа и там было бы всё ясно и однозначно.
В общем, нужен опыт и всё станет хорошо.

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


Ссылка на сообщение
Поделиться на другие сайты
Цитата(Flip-fl0p @ May 10 2018, 12:01) <{POST_SNAPBACK}>
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

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


Ссылка на сообщение
Поделиться на другие сайты
Цитата(Flip-fl0p @ May 10 2018, 08:01) <{POST_SNAPBACK}>
Сейчас Вы выбрали самый сложный стиль описания, где допустить ошибку очень и очень просто.
Я придерживаюсь прямо противоположного взгляда. Ничего простого и удобного в размазывании КА по нескольким процессам не вижу.

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


Ссылка на сообщение
Поделиться на другие сайты
Цитата(andrew_b @ May 10 2018, 09:36) <{POST_SNAPBACK}>
Я придерживаюсь прямо противоположного взгляда. Ничего простого и удобного в размазывании КА по нескольким процессам не вижу.

У Вас опыта гораздо больше biggrin.gif.
Согласен, что несколько неудобно, т.к описание такого КА получается достаточно громоздким. Но при разделении автомата на 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-схема:


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

Только теперь значение 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-схема:


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



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

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


Ссылка на сообщение
Поделиться на другие сайты
Код
Как я понял квартус ругается на наличие latch, но именно так я и планировал.

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

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


Ссылка на сообщение
Поделиться на другие сайты
Цитата(Flip-fl0p @ May 10 2018, 15:13) <{POST_SNAPBACK}>
Код
Как я понял квартус ругается на наличие 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-схема:



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



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

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


Ссылка на сообщение
Поделиться на другие сайты
Цитата(Sprite @ May 10 2018, 09:38) <{POST_SNAPBACK}>
Код
//---------------------------
// Блок-защелка данных
//---------------------------
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;

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

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


Ссылка на сообщение
Поделиться на другие сайты
Цитата(Marat Zuev @ May 10 2018, 15:56) <{POST_SNAPBACK}>
Это - не защёлка, а 15 параллельных триггеров:
Код
always @ (posedge clk)
    data_out_reg = state == S4 ? data_in : data_out_reg;

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


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

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


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

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти