📜  Verilog优先级编码器

📅  最后修改于: 2021-01-11 15:18:55             🧑  作者: Mango

Verilog优先编码器

编码器是组合电路。它具有2 ^ n条输入线和n条输出线。它占用这2 ^ n个输入数据,并将它们编码为n位数据。并产生等效于输入线的二进制代码,该输入线为高电平有效。

但是,普通的编码器有问题。如果多于一条逻辑值为1的输入线,它将对错误的输出进行编码。仅当其中一个输入为高时,它才起作用。在多个高输入的情况下,它会发生故障。

因此,为解决上述缺点,我们“优先”确定每个输入的级别。因此,如果选择了多条输入线,则输出代码将对应于具有最高指定优先级的输入。这种类型的编码器称为优先级编码r。

module pr_en ( input [7:0] a,
               input [7:0] b,
               input [7:0] c,
               input [7:0] d,
               input [1:0] sel,
               output reg [7:0] out);

   always @ (a or b or c or d or sel) begin
      if (sel == 2'b00)
         out <= a;
      else if (sel == 2'b01)
         out <= b;
      else if (sel == 2'b10)
         out <= c;
      else
         out <= d;
   end
endmodule

硬件原理图

试验台

测试平台是用于测试另一个模块的HDL模块,称为被测设备(DUT) 。测试台包含将输入应用于DUT并检查是否产生正确输出的语句。

输入和所需的输出模式称为测试向量。以下是优先级编码器的测试平台:

module tb_4to1_mux;
   reg [7:0] a;
   reg [7:0] b;
   reg [7:0] c;
   reg [7:0] d;
   wire [7:0] out;
   reg [1:0] sel;
   integer i;

   pr_en    pr_en0 (   .a (a),
                           .b (b),
                           .c (c),
                           .d (d),
                           .sel (sel),
                           .out (out));

   initial begin
      sel <= 0;
      a <= $random;
      b <= $random;
      c <= $random;
      d <= $random;

      for (i = 1; i < 4; i=i+1) begin
         #5 sel <= i;
      end

      #5 $finish;
   end
endmodule

现在,我们将看到如何在Verilog中使用不同的建模样式设计4:2优先级编码器。

1.门级建模

实际上,这是设计人员用于实现最低级别模块的最低抽象层,因为交换机级别的建模并不常见。顾名思义,门级建模利用了Verilog中可用的门原语。

下面我们描述使用门级建模的优先编码器:

从电路中,我们可以看到设计需要一个与门,两个或门和一个非门。让我们开始编码。

4:2优先级编码器的门级建模

与任何Verilog代码一样,我们首先声明模块和终端端口。

module priority_encoder_42(A0,A1,Y0,Y1,Y2,Y3);
....
endmodule

请注意,我们先声明输出,然后声明输入,因为内置门也遵循相同的模式。让我们声明输入和输出端口。

input Y3, Y2, Y1, Y0;
output A0, A1;

现在,我们可以声明中间信号了。这些不是终端端口的信号。在上述电路中,来自非门和与门的信号被视为中间信号。

wire y2bar; //not of y2 
wire and_out; // and of y2bar and y1

现在我们定义逻辑门。我们使用gate( )语法来使用Verilog中的内置Gates。

not(y2bar, y2);
and(and_out, y2bar, y1);
or(A1, Y3, Y2);
or(A0, and_out, Y3);

因此,我们的最终代码如下所示:

module priority_encoder_42(A0,A1,Y0,Y1,Y2,Y3);
input Y3, Y2, Y1, Y0;
output A0, A1;
wire y2bar;                   //not of y2 
wire and_out;               // and of y2bar and y1
not(y2bar, y2);
and(and_out, y2bar, y1);
or(A1, Y3, Y2);
or(A0, and_out, Y3);
endmodule

2.数据流建模

在这种建模技术中,我们使用逻辑方程式描述从输入到输出的数据流。我们不必理会组成电路的门。

因此,由于不需要知道实际的物理布局,使用这种抽象级别构造复杂的电路要容易得多。

它使用assign关键字通过逻辑方程式描述电路。

优先级编码器的逻辑公式为:

A1 = Y3 + Y2
A0 = Y3 + Y1Y2?

4:2优先编码器的数据流建模

与往常一样,我们从模块和端口声明开始:

module priority_encoder_datafloe(A0,A1,Y0,Y1,Y2,Y3);
input Y0,Y1,Y2,Y3;
output A0,A1;

现在,我们必须使用assign描述到输出的数据流。

assign A1 = Y3 + Y2;
assign A0 = Y3 + ((~Y2)&Y1);

因此,我们的最终代码:

module priority_encoder_datafloe(A0,A1,Y0,Y1,Y2,Y3);
input Y0,Y1,Y2,Y3;
output A0,A1;

assign A1 = Y3 + Y2;
assign A0 = Y3 + ((~Y2)&Y1);
endmodule

3.行为建模

行为建模是Verilog HDL中的最高抽象级别。我们只要知道其工作原理就可以描述电路。而且我们不需要知道逻辑电路或逻辑方程式。真值表如下所示:

Y3 Y2 Y1 Y0 A1 A0
0 0 0 1 0 0
0 0 1 X 0 1
0 1 X X 1 0
1 X X X 1 1

有了这个真值表,我们可以使用Verilog设计优先级编码器。

4:2优先级编码器的行为建模

让我们从模块和端口声明开始。

module priority_encoderbehave(A, Y);
input [3:0]Y;
output reg [1:0]A;

我们不得不提到输出作为行为建模中的reg。在这种建模方式中使用过程分配时,我们必须确保输出保留其值,直到将下一个值赋给它们为止。

always@(Y)
begin
....
end

我们在方括号中声明的是灵敏度列表。在此,取决于Y的值。 always关键字将确保每次触发敏感度列表时,语句都将执行。

beginend之间,我们编写了有关系统工作方式的过程:

casex(Y)
4'b0001:A = 2'b00;
4'b001x:A = 2'b01;
4'b01xx:A = 2'b10;
4'b1xxx:A = 2'b11;
default:$display("Error!");
endcase

案例将表达式与一系列案例进行比较,并执行与第一个匹配案例相关联的语句或语句组。我们使用过casex ,它是case的特殊版本。这将x和z值视为无关紧要。

module priority_encoderbehave(A, Y);
input [3:0]Y;
output reg [1:0]A;
always@(Y)
begin
casex(Y)
4'b0001:A = 2'b00;
4'b001x:A = 2'b01;
4'b01xx:A = 2'b10;
4'b1xxx:A = 2'b11;
default:$display("Error!");
endcase
end
endmodule

4.结构建模

结构建模描述了数字系统的硬件结构。它有点类似于门级建模。唯一的区别是它不包含任何内置门。我们为每个门创建单独的模块,然后集成以形成整个电路。

逻辑电路

对于4:2优先级编码器,我们需要两个OR,一个AND和一个NOT门。

4:2优先编码器的结构建模

首先从代码开始,我们将对“或”门进行结构化。

我们将该模块声明为or_gate。然后,我们声明输入和输出端口

module or_gate(c,a,b);
input a,b
output c;

然后,我们使用assign语句为OR编写逻辑表达式。

assign c = a|b;

因此,我们的“或”门模块将是:

module or_gate(c,a,b);
input a,b;
output c;
assign c = a|b;
endmodule

同样,我们对AND门执行操作:

module and_gate(z,x,y);
input x,y;
output z;
assign z = x&y;
endmodule 

而不是门:

module not_gate(f,e);
input e;
output f;
assign f = ~e;
endmodule

注意:我们在一个模块中保留与其他模块不同的用于分配输入和输出的变量。它确保在仿真过程中不会发生信号混合。

现在我们可以将优先级编码器描述为顶层模块。

与往常一样,从模块和端口声明开始。

module priority_encoder_struct(A0,A1,Y0,Y1,Y2,Y3);
input Y0, Y1, Y2, Y3;
output A0,A1;

现在,将这些用于逻辑门的单独模块组合为一个单独的模块作为顶部模块。这是借助模块实例化概念完成的,在该概念中,使用下部模块构建顶部模块。

使用逻辑电路,我们将使用端口名实例化此顶部中的下部模块。

not_gate u1(.f(y2bar), .e(y2));
and_gate u2(.z(w1), .x(y2bar), .y(y1));
or_gate(.c(A1), .a(Y3), .b(Y2));
or_gate(.c(A0), .a(Y1), .b(w1));

因此,结构形式的优先级编码器的Verilog代码为:

module or_gate(c,a,b);
input a,b;
output c;
assign c = a|b;
endmodule
module not_gate(f,e);
input e;
output f;
assign f = ~e;
endmodule
module and_gate(z,x,y);
input x,y;
output z;
assign z = x&y;
endmodule 
module priority_encoder_struct(A0,A1,Y0,Y1,Y2,Y3);
input Y0, Y1, Y2, Y3;
output A0,A1;
not_gate u1(.f(y2bar), .e(y2));
and_gate u2(.z(w1), .x(y2bar), .y(y1));
or_gate(.c(A1), .a(Y3), .b(Y2));
or_gate(.c(A0), .a(Y1), .b(w1));
endmodoule