我想在一个始终块中使用另一个模块的输出。目前,使此代码工作的唯一方法是在pi_in分配之后添加#1,以便有足够的时间让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?
本质上,我希望只有在pi模块以pi_In(=8*i+j)作为输入完成其工作后,才评估PermutedBitNo=pi_out。我怎样才能挡住这条线直到Pi完成?
我必须用时钟吗?如果是这样的话,请给我一个提示。
更新:
根据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
这是一个不错的软件。。。
事实上,这种语言描述硬件是没有帮助的。
在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_in
时对pi_out
进行采样。在数字设计中,这意味着您希望在发送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_in
之后一个时钟循环获得pi_out
的新值
编辑
首先,在编写(同步)进程时,我建议您逐个进程只处理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个周期是有道理的。
为了纠正这种情况,您应该去掉同步进程中的"逻辑"部分。正如你在评论中所说的那样,这是合乎逻辑的,所以它不应该在同步过程中。
希望它能帮助