当我在verilog中使用条件操作时,我收到错误

时间:2016-11-30 15:14:03

标签: verilog system-verilog hdl

这是一个微不足道的问题,但经过大量的努力,我想把它放在这里。

在我的代码中,我使用条件运算符编写了一行,如下所示:

assign {RS2, RS1} = (!DisM || !DisX)? (RdEn==2'b00? (!DisI? {rs2, rs1} : 64'bz) : (RdEn==2'b01? (!switch? {rs2, Rn} : {Rn, rs1}) : {Rm, Rn}))) : 64'bz;
  1. RS2& RS1是32位输出线。
  2. Rn& Rm是32位输入。
  3. rs1& rs2是32位寄存器。
  4. RdEn是2位寄存器。
  5. DisI和switch是一位寄存器。
  6. enter image description here

    模拟器(Icarus 0.9.7或任何)显示上述行中存在语法错误。 请帮帮我。

    提前致谢。

    这是我的代码,它解决了同样的问题:

    module TEST(Rn, Rm, DisM, DisX, DisI, switch, RdEn, RS1, RS2);
    input [31:0]Rn, Rm;
    input DisM, DisX, DisI, switch;
    input [1:0]RdEn;
    output [31:0]RS1, RS2;
    
    reg [31:0]rs1, rs2;
    
    always@*
    begin
        rs1 = Rn + 32'd7;
        rs2 = Rm - 32'd7;
    end
    
    assign {RS2, RS1} = (!DisM || !DisX)? (RdEn==2'b00? (!DisI? {rs2, rs1} : {64{1'bz}}) : (RdEn==2'b01? (!switch? {rs2, Rn} : {Rn, rs1}) : {Rm, Rn}))) : {64{1'bz}};
    
    endmodule
    

2 个答案:

答案 0 :(得分:2)

编译器将?中的RdEn==2'b00?解释为第3位,而不是作为三元运算符。只需在b00?之间添加空格即可。与b01?相同。

?是有效的z_digit。请参阅IEEE Std 1800-2012,第5.7节“数字”。

此外,您的括号数量不匹配(一个好的编辑器可以显示这个):

assign {RS2, RS1} = (!DisM || !DisX)? (RdEn==2'b00 ? (!DisI? {rs2, rs1} : {64{1'bz}}) : (RdEn==2'b01 ? (!switch? {rs2, Rn} : {Rn, rs1}) : {Rm, Rn})) : {64{1'bz}};

使用{64{1'bz}}确保获得64位1'bz也是一种好习惯。

答案 1 :(得分:1)

虽然您已经接受了答案,但我强烈建议您重新编码。因为它很难阅读,因而很难调试。至少添加返回行和缩进,以便条件易于在视觉上配对。例如,以下是工具的解决方案的副本,其中添加了换行符和空格。请注意这种格式化样式不会发生RdEn==2'b00?问题。像emacs和vim这样的编辑器都有语法插件,可以帮助缩进格式化。

assign {RS2, RS1} = (!DisM || !DisX)
  ? (RdEn==2'b00
    ? (!DisI ? {rs2, rs1} : {64{1'bz}})
    : (RdEn==2'b01
        ? (!switch ? {rs2, Rn} : {Rn, rs1})
        : {Rm, Rn}))
  : {64{1'bz}};

实际上,我发现条件运算符?:(w / o high-Z)在合成时通常会显式为2:1多路复用,这对于时序和面积可能不是最佳的。我还发现保持三态分配简单可以得到更清晰的结果。

我通常建议的方法是确定与三态分配分开的输出使能和输出数据。合成器通常使用这种方法比一个长的赋值语句做得更好;至少从我的经验来看。如果你有一个有限数量的三态驱动器,这种方法也很好,这在FPGA中很常见。

wire out_en = (!DisM || !DisX) && !(RdEn==2'b00 && !DisI);
reg [63:0] out_data;
always @* begin
  case(RdEn)
    2'b00 : out_data = {rs2, rs1};
    2'b01 : out_data = !switch ? {rs2, Rn} : {Rn, rs1});
    default : out_data = {Rm, Rn};
  endcase
end
assign {RS2, RS1} = out_en ? out_data : {64{1'bz}};

偶尔并行的三态驱动程序具有非重叠启用功能,可以更好地满足某些设计标准。这种方法可以根据技术节点和架构减少时序。通常会有一个区域被击中,如果加载很多,它可能会对时间产生负面影响。

assign {RS2, RS1} = ((!DisM || !DisX) && RdEn==2'b00 && !DisI)   ? {rs2, rs1} : {64{1'bz}};
assign {RS2, RS1} = ((!DisM || !DisX) && RdEn==2'b01 && !switch) ? {rs2,  Rn} : {64{1'bz}};
assign {RS2, RS1} = ((!DisM || !DisX) && RdEn==2'b01 &&  switch) ? { Rn, rs1} : {64{1'bz}};
assign {RS2, RS1} = ((!DisM || !DisX) && RdEn[1])                ? { Rm,  Rn} : {64{1'bz}};

无论采用何种方法,都要确保三态的启用控制无故障。如果信号不干净,可能会导致总线争用。理想情况下,使能信号应该是直接触发。失败的使能信号在实践中并不总是可行的,因此您需要密切关注它。您通常不会在RTL仿真中看到潜在的故障。如果存在问题,您的综合报告可能会有一些见解。