我对verilog有些新手,我尝试运行此代码,但它给了我一个错误:
module enc(in,out);
input [7:0] in;
output [3:0] out;
reg i;
reg [3:0] out;
always @*
begin
for (i=0;i<7;i=i+1)
begin
if ((in[i]==1) && (in[7:i+1]==0))
out = i;
else
out = 0;
end
end
endmodule
我认为它在[7:i + 1]中抱怨但我不明白为什么? 有人可以建议..
修改 好吧所以我不愿意使用X,因为他们遇到了很多问题。我正在考虑将代码修改为:
module enc(in,out);
input [7:0] in;
output [2:0] out;
reg i;
reg [2:0] out,temp;
always @*
begin
temp = 0;
for (i=0;i<8;i=i+1)
begin
if (in[i]==1)
temp = i;
end
out = temp;
end
endmodule
你认为这会奏效吗?我目前无法访问模拟器..
答案 0 :(得分:1)
如果两个或多个位满足条件,则优先级编码器意味着将优先级赋予一位。查看代码,您似乎希望在使用向上计数器时优先考虑LSB。每次看都会分配out
,所以即使你可以编译,最终的结果也是6或0。
对于LSB优先级编码器,首先使用out
的默认值启动并使用向下计数器:
module enc (
input wire [7:0] in,
output reg [2:0] out
);
integer i;
always @* begin
out = 0; // default value if 'in' is all 0's
for (i=7; i>=0; i=i-1)
if (in[i]) out = i;
end
endmodule
答案 1 :(得分:1)
如果您只对模拟感兴趣,那么线性循环方法应该没问题,例如
out = 0;
for (i = W - 1; i > 0; i = i - 1) begin
if (in[i] && !out)
out = i;
end
如果你也关心表现,问题会变得更有趣。我曾尝试过编写参数化优先编码器here的不同方法。事实证明,Synopsys甚至可以从上面的脑死循环中生成有效的实现,但其他工具链需要显式生成魔法。以下是该链接的摘录:
output [WIDTH_LOG - 1:0] msb;
wire [WIDTH_LOG*WIDTH - 1:0] ors;
assign ors[WIDTH_LOG*WIDTH - 1:(WIDTH_LOG - 1)*WIDTH] = x;
genvar w, i;
integer j;
generate
for (w = WIDTH_LOG - 1; w >= 0; w = w - 1) begin
assign msb[w] = |ors[w*WIDTH + 2*(1 << w) - 1:w*WIDTH + (1 << w)];
if (w > 0) begin
assign ors[(w - 1)*WIDTH + (1 << w) - 1:(w - 1)*WIDTH] = msb[w] ? ors[w*WIDTH + 2*(1 << w) - 1:w*WIDTH + (1 << w)] : ors[w*WIDTH + (1 << w) - 1:w*WIDTH];
end
end
endgenerate
答案 2 :(得分:0)
为了能够在part-slice后缀中使用变量索引,必须将for块括在一个generate块中,如下所示:
gen var i;
generate
for (i=0;i<7;i=i+1) begin :gen_slices
always @* begin
... do whatever with in[7:i+1]
end
end
问题在于,将它写入您的模块,它的编写方式会导致其他错误。你重写的模块看起来像这样(警告:这也行不通)
module enc (
input wire [7:0] in,
output reg [2:0] out // I believe you wanted this to be 3 bits width, not 4.
);
genvar i; //a generate block needs a genvar
generate
for (i=0;i<7;i=i+1) begin :gen_block
always @* begin
if (in[i]==1'b1 && in[7:i+1]=='b0) // now this IS allowed :)
out = i;
else
out = 3'b0;
end
end
endgenerate
endmodule
这将引发一个综合错误,即out
来自多个来源。这意味着分配给out
的值同时来自多个来源,这是不允许的。
这是因为for
块展开了类似这样的内容:
always @* begin
if (in[0]==1'b1 && in[7:1]=='b0)
out = 0;
else
out = 3'b0;
end
always @* begin
if (in[1]==1'b1 && in[7:2]=='b0)
out = 1;
else
out = 3'b0;
end
always @* begin
if (in[2]==1'b1 && in[7:3]=='b0)
out = 2;
else
out = 3'b0;
end
.... and so on...
现在你有多个组合块(always @*
)试图将值设置为out
。所有这些都将同时工作,并且所有这些都会尝试将out
块的具体值设为if
块评估为true
或false
。回想一下,每个if
语句的条件与其他if
条件相互排斥(即只有一个if
必须评估为true
)。
因此,如果if
块不会分配它,那么快速而又脏的方法来避免这种多源情况(我确信有更优雅的方法来解决这个问题)就是让它变为高阻抗一个值。像这样:
module enc (
input wire [7:0] in,
output reg [2:0] out // I believe you wanted this to be 3 bits width, not 4.
);
genvar i; //a generate block needs a genvar
generate
for (i=0;i<7;i=i+1) begin :gen_block
always @* begin
if (in[i]==1'b1 && in[7:i+1]=='b0) // now this IS allowed :)
out = i;
else
out = 3'bZZZ;
end
end
endgenerate
always @* begin
if (in[7]) // you missed the case in which in[7] is high
out = 3'd7;
else
out = 3'bZZZ;
end
endmodule
另一方面,如果您只需要一个优先编码器,并且您的设计使用固定宽度和小宽度的输入和输出,您可以编写您的编码器:
module enc (
input wire [7:0] in,
output reg [2:0] out
);
always @* begin
casex (in)
8'b1xxxxxxx : out = 3'd7;
8'b01xxxxxx : out = 3'd6;
8'b001xxxxx : out = 3'd5;
8'b0001xxxx : out = 3'd4;
8'b00001xxx : out = 3'd3;
8'b000001xx : out = 3'd2;
8'b0000001x : out = 3'd1;
8'b00000001 : out = 3'd0;
default : out = 3'd0;
endcase
end
endmodule
(虽然似乎有理由不在设计中使用casex
。请阅读@Tim在其他问题中发表的评论:How can I assign a "don't care" value to an output in a combinational module in Verilog)
总结:我担心我没有针对你的要求的防弹设计(如果我们考虑到蒂姆在评论中链接的论文的内容),但至少,你现在知道为什么{{在部分切片后缀中不允许使用1}}。
另一方面,你可以通过研究我给出的代码作为另一个SO问题的答案来完成一半的工作。在这种情况下,模块的工作方式类似于优先级编码器,参数化且没有i
语句,只有输出不是二进制,而是单热编码。
How to parameterize a case statement with don't cares?
答案 3 :(得分:0)
所以我编辑的解决方案有效......多么愚蠢!我忘了宣布reg [2:0] i;而是写了reg i; 谢谢大家
答案 4 :(得分:0)
帅哥,我必须告诉你,您所有的解决方案要么太复杂,要么无法合成,或者实施到慢速多路复用器中。 OpenCores的Alexej Bolshakov于2015年8月23日上传了基于OR元素的出色参数化编码器。无多路复用器,可100%合成。他的代码(采用我的小格式):
module encoder #(
parameter LINES = 16,
parameter WIDTH = $clog2(LINES)
)(
input [LINES-1:0] unitary_in,
output wor [WIDTH-1:0] binary_out
);
genvar i, j;
generate
for (i = 0; i < LINES; i = i + 1)
begin: loop_i
for (j = 0; j < WIDTH; j = j + 1)
begin: loop_j
if (i[j])
assign binary_out[j] = unitary_in[i];
end
end
endgenerate
endmodule
答案 5 :(得分:0)
此解决方案将输入分为四个块,并检查第一个非零块。以相同的方式进一步细分该块。这是相当有效的。
// find position of most significant 1 bit in 64 bits input
// (system verilog)
module bitscan(
input logic [63:0] in, // number input
output logic [5:0] out, // bit position output
output logic zeroout // indicates if input is zero
);
logic [63:0] m0; // intermediates
logic [15:0] m1;
logic [3:0] m2;
logic [5:0] r;
always_comb begin
m0 = in;
// choose between four 16-bit blocks
if (|m0[63:48]) begin
m1 = m0[63:48];
r[5:4] = 3;
end else if (|m0[47:32]) begin
m1 = m0[47:32];
r[5:4] = 2;
end else if (|m0[31:16]) begin
m1 = m0[31:16];
r[5:4] = 1;
end else begin
m1 = m0[15:0];
r[5:4] = 0;
end
// choose between four 4-bit blocks
if (|m1[15:12]) begin
m2 = m1[15:12];
r[3:2] = 3;
end else if (|m0[11:8]) begin
m2 = m1[11:8];
r[3:2] = 2;
end else if (|m0[7:4]) begin
m2 = m1[7:4];
r[3:2] = 1;
end else begin
m2 = m1[3:0];
r[3:2] = 0;
end
// choose between four remaining bits
if (m2[3]) r[1:0] = 3;
else if (m2[2]) r[1:0] = 2;
else if (m2[1]) r[1:0] = 1;
else r[1:0] = 0;
out = r;
zeroout = ~|m2;
end
endmodule
这是另一种使用资源较少的解决方案:
module bitscan4 (
input logic [63:0] in,
output logic [5:0] out,
output logic zout
);
logic [63:0] m0;
logic [3:0] m1;
logic [3:0] m2;
logic [5:0] r;
always_comb begin
r = 0;
m0 = in;
if (|m0[63:48]) begin
r[5:4] = 3;
m1[3] = |m0[63:60];
m1[2] = |m0[59:56];
m1[1] = |m0[55:53];
m1[0] = |m0[51:48];
end else if (|m0[47:32]) begin
r[5:4] = 2;
m1[3] = |m0[47:44];
m1[2] = |m0[43:40];
m1[1] = |m0[39:36];
m1[0] = |m0[35:32];
end else if (|m0[31:16]) begin
r[5:4] = 1;
m1[3] = |m0[31:28];
m1[2] = |m0[27:24];
m1[1] = |m0[23:20];
m1[0] = |m0[19:16];
end else begin
r[5:4] = 0;
m1[3] = |m0[15:12];
m1[2] = |m0[11:8];
m1[1] = |m0[7:4];
m1[0] = |m0[3:0];
end
if (m1[3]) begin
r[3:2] = 3;
end else if (m1[2]) begin
r[3:2] = 2;
end else if (m1[1]) begin
r[3:2] = 1;
end else begin
r[3:2] = 0;
end
m2 = m0[{r[5:2],2'b0}+: 4];
if (m2[3]) r[1:0] = 3;
else if (m2[2]) r[1:0] = 2;
else if (m2[1]) r[1:0] = 1;
else r[1:0] = 0;
zout = ~|m2;
out = r;
end
endmodule