Регистры Сдвига 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
2 ответов:
Во-первых, не забывай свой
begin-ends вокруг разделов кода:Без этого в предложенииelse begin r_reg[0]=data; r_reg = r_reg<<1; endelseоператора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; endbegin/endв операторахif/else, чтобы избежать этой путаницы.Способ, которым он имитирует,
r_regвсегда равен 0, потому что вы колотите 1-е задание (r_reg[0]=data;) со 2-м (r_reg = r_reg<<1;). Другое отличие состоит в том, что книга присваиваетdataMSB сдвигового регистра, а вы присваиваете его LSB.Если вы используете приличные инструменты линтинга и синтеза, вы, вероятно, получите кучу предупреждений для вашего кода. Это бы вас насторожило чтобы внести некоторые изменения.
Comments