【问题标题】:Verilog - how to negate an array?Verilog - 如何否定一个数组?
【发布时间】:2015-04-05 16:49:29
【问题描述】:
reg a[4:0];
reg inv_a[4:0];

assign inv_a = ~a; //This doesn't work.

当我使用上述语句尝试 modelsim 时,它会抛出:“Illegal operation on unpacked types”

有人可以指出如何正确否定 Verilog 中的数组吗?


编辑:提供更多信息,这会改变任何建议吗?

module router_main(
    input bustorouter_ready[4:0],
);

  wire inv_bustorouter_ready[4:0];

  assign inv_bustorouter_ready = ~bustorouter_ready; //Still doesn't work.

【问题讨论】:

    标签: verilog system-verilog


    【解决方案1】:

    一种通过位流实现对解包数组进行反转的单行解决方案(请参阅IEEE Std 1800-2012 & sect; 11.4.14 流操作符(打包/解包)了解完整详情)

    logic a[4:0];
    logic inv_a[4:0];
    
    assign {<<{inv_a}} = ~{<<{a}}; // bit streaming
    

    比特流仅适用于 SystemVerilog。如果您仅限于 Verilog,则必须使用 for-loop 或 generate-for-loop(请参阅 Tudor 的 answer)。

    要考虑的另一件事是是否需要解压数组。打包数组允许访问整个数组。 Verilog 不允许通过端口连接传递解包数组,允许打包数组。 SystemVerilog 支持打包在未打包的数组中作为端口。

    reg [4:0] a;
    reg [4:0] inv_a;
    
    assign inv_a = ~a; // pack array
    

    一般归结为您希望如何访问数组。如果您想被视为一个数字,请使用打包数组;仍然允许访问单个元素。如果您只打算访问数组中的单个元素,请使用 unpacked。有关打包与未打包的更多信息,请参阅这些较早回答的问题:

    【讨论】:

      【解决方案2】:

      尝试在组合过程中使用for 循环:

      always_comb
        for (int i = 0; i <= 4; i++)
          inv_a[i] = ~a[i];
      

      因为我猜你在做设计,你需要检查你的综合工具是否支持这个结构。

      您也可以使用generate:

      genvar i;
      for (i = 0; i <= 4; i++)
        always_comb
          inv_a[i] = ~a[i];
      

      【讨论】:

      • 这基本上就是我现在正在做的事情。我想如果几天后没有一个班轮,我会接受你的回答!
      【解决方案3】:

      将您的reg 更改为wire,因为assign 需要:

      reg [4:0] a;
      wire [4:0] inv_a;
      
      assign inv_a = ~a; //This should work.
      

      或者,如果您使用always 块,您可以将inv_a 保留为reg

      reg [4:0] a;
      reg [4:0] inv_a;
      
      always @*
        inv_a = ~a; //This should work.
      

      reg a[4:0] 好像和reg [4:0] a 不一样;

      reg a[4:0]reg [0:0] a[4:0] 相同:由 5 个寄存器组成的数组,每个寄存器 1 位。

      reg [4:0] a 是一个 5 位寄存器。

      归约运算符以及一元反相运算符(这是按位的)仅对单个向量(寄存器)进行操作。您的第一个声明声明了 5 个向量。

      【讨论】:

      • 请查看我更新的问题。我试过你的建议,但它仍然不起作用。我添加了有关我的代码的更多信息,请查看您的建议是否仍然适用?
      • 你不应该使用always @*,因为关联的块不会在时间0被调用。如果你使用SystemVerilog,你应该使用always_comb
      • 对于我的设计,我实际上需要一个由 5 个寄存器组成的数组,因为信号来自不同的模块。
      【解决方案4】:

      您只能对压缩数组(位向量)执行逻辑操作。解包数组作为一个整体允许的唯一操作是复制和比较。

      如果您必须在一行中执行此操作,则可以将解压缩数组转换为压缩数组并返回。

      typedef logic  ua5[5];
      typedef logic bit [4:0] pa5;
      ua5 a; // same as reg a[4:0]
      ua5 inv_a;
      
      assign inv_a = ua5'(pa'(~a));
      

      否则,我会推荐一个 foreach 循环

      always_comb foreach (a[i]) inv_a[i] = ~a;
      

      【讨论】:

      • 不应该foreach循环~a吗?我认为这是迄今为止最干净的答案。
      【解决方案5】:

      你可以用一个数组异或它:

      assign inv_a = a ^ {WIDTH{1'b1}};
      

      【讨论】:

        【解决方案6】:

        您可以通过对打包数组使用逻辑运算来进行反转。

        assign inverted_a = ((a)^(4'b1111));
        X (XOR) 1 = ~X 
        

        然后您可以将二进制数编辑为输入或寄存器的宽度 喜欢7'b111111113'b111

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-04-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多