Сдвиговые регистры Verilog - PullRequest
       100

Сдвиговые регистры Verilog

4 голосов
/ 19 августа 2010

Я очень плохо знаком с языком HDL.У меня есть вопрос о том, как программировать сдвиговый регистр.(Я знаю, что я перехожу в другом направлении).Почему книга использует wire[N-1:0] r_next?в чем недостаток моей реализации?спасибо

моя первая попытка выглядит следующим образом

module lesson04#(parameter N=8)(
    input wire clk, reset,
    input wire data,
    output wire out
);

reg [N-1: 0] r_reg;


always @(posedge clk or negedge reset)
begin
    if(!reset)
         r_reg =0;
    else 
        r_reg[0]=data;
        r_reg = r_reg<<1;
end

assign out =r_reg[N-1];
endmodule 

но книга дает:

module lesson04#(parameter N=8)(
    input wire clk, reset,
    input wire data,
    output wire out
);

reg [N-1: 0] r_reg;
wire[N-1:0] r_next;

always @(posedge clk or negedge reset)
begin
    if(!reset)
         r_reg =0;
    else 
        r_reg <= r_next;
end

assign r_next= {data, r_reg[N-1:1]};
assign out =r_reg[N-1];
endmodule

Ответы [ 2 ]

6 голосов
/ 19 августа 2010

Прежде всего, не забывайте свои begin - end s вокруг разделов кода:

else begin
     r_reg[0]=data;
     r_reg = r_reg<<1;
end

Без этого только r_reg[0]=data будет в предложении elseif заявление.Это будет работать, но считается плохим стилем из-за операторов блокировки в описании последовательной логики ...

Во-вторых, для моделирования последовательных блоков используйте неблокирующие назначения (<=), иначе ваши вычисления могут «провалиться».'(Google неблокирует против блокировки для получения дополнительной информации).Ваш пример может очень хорошо сработать (вы пробовали это в симуляторе?), Но если все усложняется и добавляется больше переменных, то все может сломаться.

always @(posedge clk or negedge reset)
begin
    if(!reset)
         r_reg <= 0;
    else begin // This is horrible! Don't write code like this!
        r_reg[0] = data;     // blocking
        r_reg <= r_reg<<1;   // non-blocking
    end
end

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

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

Кроме того, если ваш сброс активен на низком уровне (т.е. сбрасывается LOW), он долженбыть названным таковым, например resetb или reset_n.

3 голосов
/ 19 августа 2010

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

По тому, как вы отступили в always блок, меня заставляют поверить, что это не то, что ты хотел.Вот как в действительности ведет себя ваш блок:

always @(posedge clk or negedge reset)
begin
    if(!reset) begin
         r_reg =0;
    end else begin
        r_reg[0]=data;
    end
    r_reg = r_reg<<1;
end

Я всегда явно использую ключевые слова begin/end в операторах if/else, чтобы избежать этой путаницы.

Способ, которым он симулирует, r_regвсегда 0, потому что вы забили первое назначение (r_reg[0]=data;) со вторым (r_reg = r_reg<<1;).Другое отличие состоит в том, что книга назначает data для MSB регистра сдвига, но вы назначаете его для LSB.

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

...