Регистры Сдвига Verilog



Я очень новичок в языке 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
1138   2  

2 ответов:

Во-первых, не забывай свой begin-ends вокруг разделов кода:

else begin
     r_reg[0]=data;
     r_reg = r_reg<<1;
end
Без этого в предложении else оператора if будет только r_reg[0]=data. Это будет работать, но считается плохим стилем из-за блокирующих операторов в последовательном логическом описании... Во-вторых, для моделирования последовательных блоков используйте неблокирующие назначения (<=), иначе ваши вычисления могут "провалиться" (google nonblocking vs blocking для получения дополнительной информации). Ваш пример может очень хорошо сработать (вы пробовали это в симуляторе?) но если все усложняется и добавляется больше переменных, все может сломаться.
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.

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

По тому, как вы отступили от своего блока 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, потому что вы колотите 1-е задание (r_reg[0]=data;) со 2-м (r_reg = r_reg<<1;). Другое отличие состоит в том, что книга присваивает data MSB сдвигового регистра, а вы присваиваете его LSB.

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

Comments

    Ничего не найдено.