Verilog: дождаться оценки логики модуля в блоке всегда
Я хочу использовать вывод другого модуля внутри всегда блока. В настоящее время единственный способ заставить этот код работать - это добавить #1 после присвоения pi_in, чтобы прошло достаточно времени, чтобы Pi завершил работу.
Соответствующая часть из модуля pLayer.v:
Pi pi(pi_in,pi_out);
always @(*)
begin
for(i=0; i<constants.nSBox; i++) begin
for(j=0; j<8; j++) begin
x = (state_value[(constants.nSBox-1)-i]>>j) & 1'b1;
pi_in = 8*i+j;#1; /* wait for pi to finish */
PermutedBitNo = pi_out;
y = PermutedBitNo>>3;
tmp[(constants.nSBox-1)-y] ^= x<<(PermutedBitNo-8*y);
end
end
state_out = tmp;
end
Modllue Pi.v
`include "constants.v"
module Pi(in, out);
input [31:0] in;
output [31:0] out;
reg [31:0] out;
always @* begin
if (in != constants.nBits-1) begin
out = (in*constants.nBits/4)%(constants.nBits-1);
end else begin
out = constants.nBits-1;
end
end
endmodule
Задержки не должны использоваться в окончательной реализации, так есть ли другой способ без использования #1?
По сути, я хочу, чтобы PermutedBitNo = pi_out оценивалось только после того, как модуль Pi завершил свою работу с pi_in (=8*i+j) в качестве ввода. Как я могу заблокировать эту строку, пока Пи не закончил?
Должен ли я использовать часы? Если это так, пожалуйста, дайте мне подсказку.
Обновить:
Основываясь на предложениях Krouitch, я изменил свои модули. Вот обновленная версия:
С pLayer.v:
Pi pi(.clk (clk),
.rst (rst),
.in (pi_in),
.out (pi_out));
counter c_i (clk, rst, stp_i, lmt_i, i);
counter c_j (clk, rst, stp_j, lmt_j, j);
always @(posedge clk)
begin
if (rst) begin
state_out = 0;
end else begin
if (c_j.count == lmt_j) begin
stp_i = 1;
end else begin
stp_i = 0;
end
// here, the logic starts
x = (state_value[(constants.nSBox-1)-i]>>j) & 1'b1;
pi_in = 8*i+j;
PermutedBitNo = pi_out;
y = PermutedBitNo>>3;
tmp[(constants.nSBox-1)-y] ^= x<<(PermutedBitNo-8*y);
// at end
if (i == lmt_i-1)
if (j == lmt_j) begin
state_out = tmp;
end
end
end
endmodule
module counter(
input wire clk,
input wire rst,
input wire stp,
input wire [32:0] lmt,
output reg [32:0] count
);
always@(posedge clk or posedge rst)
if(rst)
count <= 0;
else if (count >= lmt)
count <= 0;
else if (stp)
count <= count + 1;
endmodule
Из Pi.v:
always @* begin
if (rst == 1'b1) begin
out_comb = 0;
end
if (in != constants.nBits-1) begin
out_comb = (in*constants.nBits/4)%(constants.nBits-1);
end else begin
out_comb = constants.nBits-1;
end
end
always@(posedge clk) begin
if (rst)
out <= 0;
else
out <= out_comb;
end
1 ответ
Это хорошая часть программного обеспечения у вас здесь...
Тот факт, что этот язык описывает аппаратные средства, тогда не помогает.
В verilog, то, что вы пишете, будет симулировать в нулевое время. это означает, что ваш цикл включен i
а также j
будет полностью сделано в нулевое время тоже. Вот почему вы видите что-то, когда вы заставляете цикл ждать 1 единицу времени с #1
,
Так что да, вы должны использовать часы.
Для того, чтобы ваша система работала, вам нужно реализовать счетчики для i
а также j
как я вижу вещи.
Счетчик синхронного счетчика со сбросом можно записать так:
`define SIZE 10
module counter(
input wire clk,
input wire rst_n,
output reg [`SIZE-1:0] count
);
always@(posedge clk or negedge rst_n)
if(~rst_n)
count <= `SIZE'd0;
else
count <= count + `SIZE'd1;
endmodule
Вы указываете, что вы хотите попробовать pi_out
только когда pi_in
обрабатывается. В цифровом дизайне это означает, что вы хотите подождать один такт между моментом отправки pi_in
и момент, когда вы читаете pi_out
,
Лучшее решение, на мой взгляд, это сделать ваш pi
модуль последовательный, а затем рассмотрим pi_out
в качестве регистра.
Для этого я бы сделал следующее:
module Pi(in, out);
input clk;
input [31:0] in;
output [31:0] out;
reg [31:0] out;
wire clk;
wire [31:0] out_comb;
always @* begin
if (in != constants.nBits-1) begin
out_comb = (in*constants.nBits/4)%(constants.nBits-1);
end else begin
out_comb = constants.nBits-1;
end
end
always@(posedge clk)
out <= out_comb;
endmodule
Быстро, если вы используете счетчики для i
а также j
и это последнее pi
Модуль это то, что произойдет:
- на новом такте,
i
а такжеj
изменится ->pi_in
будет меняться соответственно одновременно (в симуляции) - на следующем тактовом цикле
out_comb
будет храниться вout
и тогда у вас будет новое значениеpi_out
на один такт позжеpi_in
РЕДАКТИРОВАТЬ
Прежде всего, при написании (синхронных) процессов я бы посоветовал вам иметь дело только с 1 регистром за процессом. Это сделает ваш код более понятным и легким для понимания / отладки.
Другой совет - отделить комбинаторные схемы от последовательных. Это также сделает ваш код более понятным и понятным.
Если я возьму пример счетчика, который я написал ранее, он будет выглядеть так:
`define SIZE 10
module counter(
input wire clk,
input wire rst_n,
output reg [`SIZE-1:0] count
);
//Two way to do the combinatorial function
//First one
wire [`SIZE-1:0] count_next;
assign count_next = count + `SIZE'd1;
//Second one
reg [`SIZE-1:0] count_next;
always@*
count_next = count + `SIZE'1d1;
always@(posedge clk or negedge rst_n)
if(~rst_n)
count <= `SIZE'd0;
else
count <= count_next;
endmodule
Здесь я понимаю, почему у вас на один цикл больше, чем ожидалось, потому что вы поставили комбинаторную схему, которая управляет вашим pi
Модуль у вас синхронный процесс. Это означает, что произойдет следующее:
- первый
clk
положительный крайi
а такжеj
будет оцениваться - следующий цикл
pi_in
оценивается - следующий цикл,
pi_out
захвачен
Так что имеет смысл, что требуется 2 цикла.
Чтобы исправить это, вы должны вынуть из синхронного процесса "логическую" часть. Как вы заявили в своих комментариях, это логика, поэтому она не должна быть в синхронном процессе.
Надеюсь, поможет