译码器正好与编码器的行为相反,译码是将编码还原到本码的过程,即每组代码有一个相应输出端为有效(高/低)电平,其余输出端为无效(低/高)电平。
- 按照功能可将译码器分为:
- 变量译码器:如 2/4译码器,3/8译码器,4/16译码器等。
- 码制变换器:BCD/16,格雷码/16,
- 显示译码 :数码管,ASCII等
例1:设计3/8变量译码器 ,要求3位输入,8位输出,输出的8种组合中只有一位为1,其它为零,8种组合与3位变量的最小项一一对应,如表1:
表一:

从表一种可以看出,3/8译码器非常简单,根据真值表可以直接写出逻辑表达式,这里直接给出Verilog的代码描述。
第一种方法:与或非并发赋值
在并发语句中直接将组合逻辑赋给对应的输出变量
module dec3t8
(
input a, b, c,
output y0, y1, y2, y3, y4, y5, y6, y7
);
assign y0 = ~a & ~b & ~c;
assign y1 = ~a & ~b & c;
assign y2 = ~a & b & ~c;
assign y3 = ~a & b & c;
assign y4 = a & ~b & ~c;
assign y5 = a & ~b & c;
assign y6 = a & b & ~c;
assign y7 = a & b & c;
endmodule
第二种方法,在always过程中采用if语句译码
module dec38if
(
input [2:0] a,
output reg [7:0] y
);
always@(*)
begin
y = 8'b0;
if(a[2])
begin
if(a[1])
begin
if(a[0]) y[7] = 1'b1;
else y[6] = 1'b1;
end
else
begin
if(a[0]) y[5] = 1'b1;
else y[4] = 1'b1;
end
end
else
begin
if(a[1])
begin
if(a[0]) y[3] = 1'b1;
else y[2] = 1'b1;
end
else
begin
if(a[0]) y[1] = 1'b1;
else y[0] = 1'b1;
end
end
end
endmodule
仿真激励程序testbench
`timescale 1 ns / 1 ps
module tb_dis ();
reg [2:0] a;
wire [7:0] y;
initial
begin
a = 3'b000;
#10
$display("time =%t, a= %b, y= %b ",$time ,a, y);
a = 3'b001;
#10
$display("time =%t, a= %b, y= %b ",$time ,a,y);
a = 3'b010;
#10
$display("time =%t, a= %b, y= %b ",$time ,a, y);
a = 3'b011;
#10
$display("time =%t, a= %b, y= %b ",$time ,a, y);
a = 3'b100;
#10
$display("time =%t, a= %b, y= %b ",$time ,a, y);
a = 3'b101;
#10
$display("time =%t, a= %b, y= %b ",$time ,a,y);
a = 3'b110;
#10
$display("time =%t, a= %b, y= %b ",$time ,a, y);
a = 3'b111;
#10
$display("time =%t, a= %b, y= %b ",$time ,a,y);
end
dec38if dec38if_inst
(
.a (a),
.y (y)
);
endmodule
$display函数显示的结果

Modelsim的仿真结果:

图1
第三种方法采用always 过程中case语句实现
module dec38case
(
input [2:0] a,
output reg [7:0] y
);
always@(*)
begin
case(a)
7: y = 8'b1000_0000;
6: y = 8'b0100_0000;
5: y = 8'b0010_0000;
4: y = 8'b0001_0000;
3: y = 8'b0000_1000;
2: y = 8'b0000_0100;
1: y = 8'b0000_0010;
0: y = 8'b0000_0001;
default: y = 8'bxxxx_xxxx;
endcase
end
endmodule
在case 语句的最后使用default语句对其它情况做了8’bxxxx_xxxx的赋值,这种情况对于仿真观察非常有用,其实在真实的运行也是存在的,比如在开关输入,按键输入等都有抖动情况,对于输入从低电平到高电平过度期间存在X值的情况。修改仿真程序观察X或Z输入的情况。
仿真程序如下:
`timescale 1 ns / 1 ps
module tb_dis ();
reg [2:0] a;
wire [7:0] y;
initial
begin
a = 3'b000;
#10
$display("time =%t, a= %b, y= %b ",$time ,a, y);
a = 3'b001;
#10
$display("time =%t, a= %b, y= %b ",$time ,a, y);
a = 3'b010;
#10
$display("time =%t, a= %b, y= %b ",$time ,a, y);
a = 3'b011;
#10
$display("time =%t, a= %b, y= %b ",$time ,a, y);
a = 3'b100;
#10
$display("time =%t, a= %b, y= %b ",$time ,a, y);
a = 3'b101;
#10
$display("time =%t, a= %b, y= %b ",$time ,a, y);
a = 3'b110;
#10
$display("time =%t, a= %b, y= %b ",$time ,a, y);
a = 3'b111;
#10
$display("time =%t, a= %b, y= %b ",$time ,a, y);
a = 3'b11z;
#10
$display("time =%t, a= %b, y= %b ",$time ,a, y);
a = 3'b1xx;
#10
$display("time =%t, a= %b, y= %b ",$time ,a, y);
end
dec38case dec38case_inst
(
.a (a),
.y (y)
);
endmodule
$display 函数的显示结果:
Modelsim 波形显示结果如图2:
图2
第四种方法,不考虑输入有z,x 的情况
always @ ( * )
begin
y = 0;
y[a] = 1’b1;
end
总结:在组合电路的设计中,可以有多种方法实现,描述方式也各不相同,最终都可以达到同一个目的。其它方法还有很多,如function,task, for… loop,repeat等语法结构都可以实现。同时也要提醒一点,在顺序语句中使用了reg类型的变量,不一定就会综合成时序电路,如本文的描述最终综合结果都是组合电路。
练习题:
- 利用repeat语句实现3/8 译码器。
- 理由function实现3/8译码器
- 利用task实现3/8译码器
- 举例说明reg在什么条件下会综合成触发器?
对应视频:

