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

从表一种可以看出,3/8译码器非常简单,根据真值表可以直接写出逻辑表达式,这里直接给出Verilog的代码描述。
第一种方法:与或非并发赋值
在并发语句中直接将组合逻辑赋给对应的输出变量
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
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语句译码
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
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
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
`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语句实现
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
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输入的情况。
仿真程序如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
`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 的情况
|
1 2 3 4 5 |
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在什么条件下会综合成触发器?
对应视频:

