我正在尝试练习SystemVerilog,并尝试根据此图实现ALU(算术逻辑单元):
我在EDA游乐场在线(https://www.edaplayground.com/x/mYi)上模拟SystemVerilog代码:
ALU:
module alu(
input [31:0] a,
input [31:0] b,
input [2:0] f,
output [31:0] result,
);
/*000*/
if (f[0]==0 && f[1]==0 && f[2]===0)
begin
assign result = a & b;
end
/*001*/
else (f[0]==0 && f[1]==0 && f[2]==1)
begin
assign result = a | b;
end
/*010*/
else (f[0]==0 && f[1]==1 && f[2]==0)
begin
assign result = a + b;
end
/*011 not used*/
else (f[0]==0 && f[1]==1 && f[2]==1)
begin
assign result = -1;
end
/*100*/
else (f[0]==1 && f[1]==0 && f[2]==0)
begin
assign result = a & ~b;
end
/*101*/
else (f[0]==1 && f[1]==0 && f[2]==1)
begin
assign result = a | ~b;
end
/*110*/
else (f[0]==1 && f[1]==1 && f[2]==0)
begin
assign result = a - b;
end
/*111 slt*/
else
begin
assign result = -1;
end
endmodule
部分测试平台:
module testharness();
reg [31:0] a;
reg [31:0] b;
reg [2:0] f;
reg [31:0] result;
//DUT (Device Under Test)
alu alu_0 (
.a (a),
.b (b),
.f (f),
.result (result)
);
// Test program
initial begin
/*000*/
f[0]=0;
f[1]=1;
f[2]=0;
/*0+0*/
a[0]=0;
b[0]=0;
$display( "a (%d) + b (%d) = %d%d%d%d", a[0], b[0], result[0], result[1]);
/*000*/
f[0]=0;
f[1]=1;
f[2]=0;
/*0+1*/
a[0]=0;
b[0]=1;
$display( "a (%d) + b (%d) = %d%d", a[0], b[0], result[0], result[1]);
/*000*/
f[0]=0;
f[1]=1;
f[2]=0;
/*1+1*/
a[0]=1;
b[0]=1;
$display( "a (%d) + b (%d) = %d%d", a[0], b[0], result[0], result[1]);
$finish;
end
endmodule
我一直收到此错误:
错误VCP2000“语法错误。意外的令牌:(。预期的令牌:'???',';','always','and','assign'...。”“ design.sv” 15 9
这是行:
else (f[0]==0 && f[1]==0 && f[2]==1)
begin
assign result = a | b;
end
我看不到任何明显的东西。
谢谢
答案 0 :(得分:0)
我认为您正在使用always
陈述和连续分配来混淆组合逻辑。正如其他用户之前提到的,我也认为如果您看一下一些基本的Verilog教程会很好。 Asic-world.com上有一些很棒的教程,例如Deepak Kumar Tala的Verilog in One Day。
但是,让我尝试向您解释。在示例中,您使用的是连续赋值语句。您可以在IEEE Std 1800-2012的10.3.2节中找到有关此内容的更多信息。手册说:
网络或变量的分配应是连续且自动的。在 换句话说,只要右侧表达式中的操作数发生变化 值,则应评估整个右侧。
这里不是这种情况,因为所有赋值语句的右侧操作数都相同。它不是自动的,因为它取决于您的if语句。看看下面这个非常简单的例子。如果您始终希望result
为a & b
,则可以使用以下代码。但是,您可以想象,对于更复杂的逻辑,这变得相当冗长。
module alu(
input [31:0] a,
input [31:0] b,
output [31:0] result,
);
assign result = (a & b);
endmodule
这就是SystemVerilog提供诸如always
,always_comb
,always_latch
和always_ff
之类的程序块的原因(IEEE标准1800-2012中的第9节)。例如,您应使用always_comb
。引用手册第9.2.2.2节:
SystemVerilog提供了一个特殊的always_comb过程来进行建模 组合逻辑行为。
这样,我们可以将您的代码重写为
module alu(
input [31:0] a,
input [31:0] b,
input [2:0] f,
output [31:0] result,
);
reg [31:0] result_;
always_comb
begin
/*000*/
if (f[0]==0 && f[1]==0 && f[2]===0)
begin
result_ = a & b;
end
/*001*/
else if (f[0]==0 && f[1]==0 && f[2]==1)
begin
result_ = a | b;
end
/*010*/
else if (f[0]==0 && f[1]==1 && f[2]==0)
begin
result_ = a + b;
end
/*011 not used*/
else if(f[0]==0 && f[1]==1 && f[2]==1)
begin
result_ = -1;
end
/*100*/
else if (f[0]==1 && f[1]==0 && f[2]==0)
begin
assign result = a & ~b;
end
/*101*/
else if (f[0]==1 && f[1]==0 && f[2]==1)
begin
result_ = a | ~b;
end
/*110*/
else if (f[0]==1 && f[1]==1 && f[2]==0)
begin
result_ = a - b;
end
/*111 slt*/
else
begin
result_ = -1;
end
end // End of always_comb
assign result = result_;
endmodule
请注意,您可以连续分配wire
,但是需要将变量声明为reg
才能在Always块中使用它。这就是我使用result_
而不是直接分配result
的原因。在代码块的末尾,我连续将result_
分配给result
。 Asic-world.com在difference between regs and wires上也有一个教程。
如果您不想考虑使用reg
还是wire
,也可以使用新的关键字logic
。
编辑:正如Oldfart所指出的,我原本忘记修复if ... else语句。在代码中,您始终使用else
而不是else if
。这可能也是导致编译器向您抛出错误的直接原因。