计算结果和多路复用

时间:2009-09-08 17:44:07

标签: optimization verilog vhdl

在这里使用伪代码。这些风格是否有利有弊:

假设你有一个alu可以做添加,和,或者xor。是否有更好的代码可以一直计算可能的答案,然后根据操作码选择答案(在这种情况下是一个热门):

alu_add = a + b;
alu_and = a & b;
alu_or  = a | b;
alu_xor = a ^ b;

...

if(opcode[0])      alu_out = alu_add;
else if(opcode[1]) alu_out = alu_and;
else if(opcode[2]) alu_out = alu_or;
else if(opcode[3]) alu_out = alu_xor;

另一种方法是像这样编码:

if(opcode[0])      alu_out = a + b;
else if(opcode[1]) alu_out = a & b;
else if(opcode[2]) alu_out = a | b;
else if(opcode[3]) alu_out = a ^ b;

我也把它看作:

alu_add = a + b;
alu_and = a & b;
alu_or  = a | b;
alu_xor = a ^ b;

...

alu_out = 
  ( 8{opcode[0]} & alu_add ) |
  ( 8{opcode[1]} & alu_and ) | 
  ( 8{opcode[2]} & alu_or ) |
  ( 8{opcode[3]} & alu_xor );

这两种方法都有利弊吗,或者它们最终会出现同样的问题?

2 个答案:

答案 0 :(得分:8)

从逻辑和可读性的角度考虑这一点。前两种形式在可读性方面很好,但两者都不必要地体现优先级,并将导致更多的逻辑层次。第三种形式也不是这些指标中的任何一种。最后,没有明显的理由在这里使用单热编码而不是二进制编码。以下是我对此进行编码的方式:

parameter ALU_ADD = 2'b00;
parameter ALU_AND = 2'b01;
parameter ALU_OR  = 2'b10;
parameter ALU_XOR = 2'b11;

reg [1:0]  opcode;  // 2 bits for binary coding vs. 4 for one-hot

//及以后,在你的总是阻止:

case (opcode)  // synopsys parallel_case
    ALU_ADD: alu_out = a + b;
    ALU_AND: alu_out = a & b;
    ALU_OR:  alu_out = a | b;
    ALU_XOR: alu_out = a ^ b;
endcase

这里我明确地为ALU操作码指定了值,避免了“魔术数字”,让其他人更容易理解正在发生的事情。我还使用了case语句并应用了一个指令,该指令告诉我的综合工具只能匹配一个表达式,因此不会推断出优先级编码器。我没有命名中间信号(alu_add等),因为这些操作很简单,但是当我想要方便地访问这些信号时(例如在波形查看器中模拟后看到它们的值),我经常这样做。

您可以在优秀的this article网站(没有任何关系,只是前学生)的Sunburst Design中了解有关使用案例陈述的更多信息。

最后,关于你的问题,“让代码一直计算可能的答案然后根据操作码选择答案是否更好” - 请记住,Verilog是一种硬件描述语言。无论如何,这个页面上的所有实现都在计算所有内容。它们的不同之处在于逻辑和可读性水平。看一下this page,它表明我的实现有超出操作本身的1级逻辑,其中if-else实现有3个额外的逻辑级别。

答案 1 :(得分:2)

前两个会给出相同的逻辑,但是你会在alu_out上得到一个锁存器,因为你的if else块(你的优先级编码器)没有最终else。 (无论如何,这对于verilog都是如此)。如果您的时间紧张,您可能会遇到优先级编码器所暗示的长路径问题。

在第3版中,您将获得更“平行”的结构,这可能更适合计时。它不会锁定。

在所有三个版本中,四个操作中的每个操作都会使操作码无关紧要。这会产生影响力。

我认为第一个版本为了清晰而获胜,并且您可以在调试时获得波形查看器中的每个单独操作。除非时间,面积或功率限制受到伤害,否则编写一些不易读取的内容是毫无意义的。